AgentFS

Uploads

Upload files up to 5 TB with one request, one upload URL, or resumable parts.

Files can be up to 5 TB. POST /v1/files sends a file in one request, which is the quickest way to upload files up to 100 MiB. For anything larger, use a resumable upload: it handles up to 5 TB and picks up where it stopped. The CLI chooses for you: logged in, it sends files over 16 MB in parts, six at a time, retries each part on its own, and resumes an interrupted upload when you run the same command again.

One-shot upload

Send a multipart/form-data request to https://agentfs.cloud/v1/files:

one-shot upload
curl -sS -X POST https://agentfs.cloud/v1/files \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  -F "file=@./report.pdf" \
  -F "path=research/report.pdf" \
  -F "visibility=private" \
  -F "label=Research report"

The file part is required. Use these other parts when you need them:

PartValueNotes
pathproject/folders/name.extOptional; the first segment is the project. Requires a key.
visibilitypublic, unlisted, or privateUploads without a key are always unlisted.
expires_inA duration such as 24h or 7dRequires a key. Uploads without a key expire after 24 hours.
labelText up to 200 charactersOptional display label. Requires a key.
content_dispositioninline or attachmentDefaults to inline.
if_existserror or replaceWhat to do when path already holds a file. Defaults to error. Requires path, so it requires a key.

AgentFS infers content_type from the uploaded file and its filename. HTML, SVG, and XML files are always served from the sandboxed host s.agentfsusercontent.com, whatever type you declared. Send an Idempotency-Key header with 1–200 characters if you need a retry to return the original file instead of creating another one. Reusing that key with different content returns 409 idempotency_conflict.

Send if_exists=replace to overwrite a file you wrote earlier. The file keeps its ID, path, and hosted URL, and the response is 200 instead of 201. See Files.

A one-shot request carries up to 104,857,600 bytes (100 MiB). Larger files go through a resumable upload.

Upload without a key

To try AgentFS, or to share one file quickly, upload without an API key or an account:

upload without a key
curl -F file=@report.pdf https://agentfs.cloud/v1/files

The response is the file object, with its url. These uploads work differently from uploads with a key:

  • Each file can be up to 100 MB (104,857,600 bytes).
  • The file is unlisted: anyone with the link can open it, and nobody can browse to it.
  • The link stops working 24 hours after the upload, and the file is deleted.
  • AgentFS picks the file name from the one you uploaded, plus a short random suffix.
  • Each IP address can send 20 uploads per minute and keep up to 500 MB of files that have not expired yet.
  • You can't list, rename, replace, or delete the file afterwards.

Only the one-shot POST /v1/files works without a key, with a multipart form or a raw body. Uploading from a JSON url needs a key. path, project, prefix, if_exists=replace, expires_in, label, visibility other than unlisted, and the Idempotency-Key header need a key: sending any of them without one returns 400 api_key_required. Resumable uploads and every other endpoint need a key too.

To keep files, choose where they go, or upload anything larger than 100 MB, create an API key or run agentfs login.

Resumable upload

Create a session with JSON. A key is required for agent requests:

create an upload session
curl -sS -X POST https://agentfs.cloud/v1/uploads \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  -H "content-type: application/json" \
  -d '{
    "path": "research/video.mp4",
    "size_bytes": 50000000,
    "content_type": "video/mp4"
  }'

path and size_bytes are required. You may also send content_type, a 64-character hexadecimal sha256, visibility, expires_in, label, content_disposition, and multipart. The declared size must be positive and no greater than 5,000,000,000,000 bytes (5 TB).

multipart is a boolean that defaults to false. By default, files up to 5,000,000,000 bytes get one upload_url for a single PUT, and larger files get parts. Send "multipart": true to get parts at any size. Parts make an upload resumable: each part is sent and retried on its own, and a new run can skip the parts already stored.

The response includes fields such as:

{
  "type": "upload",
  "id": "up_8f2c",
  "file_id": "f_1a2b",
  "url": "https://f.agentfsusercontent.com/f/f_1a2b",
  "status": "active",
  "transport": "s3",
  "part_size": 50000000,
  "total_parts": 1,
  "expected_size_bytes": 50000000,
  "uploaded_parts": [],
  "expires_at": "2026-04-02T12:00:00.000Z",
  "upload_url": "https://<upload_url>",
  "upload_url_expires_at": "2026-04-01T17:55:00.000Z"
}

A session lasts 24 hours unless the file expiry is sooner. Follow what the session tells you:

  • upload_url is present: PUT the whole file there in one request.
  • transport: "s3" without upload_url: fetch part URLs with GET /v1/uploads/:id/part-urls?from=1&to=100 and PUT each part to its URL.
  • transport: "worker": PUT each part to the API, as shown below.

If you get 503 upload_unavailable, wait and create the session again.

The url in this response is where the file will live. An HTML, SVG, or XML file can move to the sandboxed host when the upload completes, so share the url from the completed file object.

If the connection drops, send the same POST /v1/uploads again with the same path and size_bytes. While the session is live, you get it back with 200 and its uploaded_parts, so you only send the parts that are missing. GET /v1/uploads/:id returns the same.

Send the bytes to upload_url

PUT the whole file to upload_url in one request. Content-Length must equal size_bytes, because the signature covers it:

upload the file
curl -sS -X PUT "$UPLOAD_URL" \
  -H "Content-Length: 50000000" \
  --data-binary @video.mp4

Storage answers 200 with an ETag, and that is the last step: AgentFS sees the file arrive and marks it ready within a few seconds. The url from the first response starts working then. Call complete, shown below, only if you need the file ready before you move on, or if you declared a sha256. If the URL expires before you finish, fetch the session again with GET /v1/uploads/:id for a fresh one and send the file again.

Upload parts

Files above 5 GB, and sessions created with "multipart": true, go up in parts. Every part is part_size bytes from the session, except the last, which is whatever remains.

Fetch up to 100 part URLs at a time and PUT each part to its URL with Content-Length set to the part's size_bytes. Parts can go up in parallel; the CLI sends six at a time. Storage records the parts; completion checks them all. A part URL that has expired answers 403: fetch fresh URLs and send the part again.

part URLs
curl -sS "https://agentfs.cloud/v1/uploads/up_8f2c/part-urls?from=1&to=100" \
  -H "Authorization: Bearer $AGENTFS_KEY"

Upload parts through the API (transport: "worker")

Number parts from 1 through total_parts. Send each part as the request body and include Content-Length:

upload part 1
curl -sS -X PUT https://agentfs.cloud/v1/uploads/up_8f2c/parts/1 \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  -H "Content-Length: $PART_SIZE" \
  --data-binary @part-001

Every part except the last must be exactly part_size bytes, and the last part exactly the bytes that remain. The response is:

{
  "part_number": 1,
  "etag": "\"part-etag\"",
  "size_bytes": 16777216
}

The same part number may be sent again; the later upload replaces the earlier part.

Complete or abort

Uploads sent to upload_url complete on their own. Part uploads need this call once every part is in place:

curl -sS -X POST https://agentfs.cloud/v1/uploads/up_8f2c/complete \
  -H "Authorization: Bearer $AGENTFS_KEY"

A successful completion returns the file object. If storage could not assemble the parts, the response is 502 upload_complete_failed, which is safe to retry: call complete again. A completion in progress can return 202 with the session object; call complete again or inspect the session with:

curl -sS https://agentfs.cloud/v1/uploads/up_8f2c \
  -H "Authorization: Bearer $AGENTFS_KEY"

Delete an unfinished session to abort it:

curl -sS -X DELETE https://agentfs.cloud/v1/uploads/up_8f2c \
  -H "Authorization: Bearer $AGENTFS_KEY"

The abort response is 204. You cannot abort a completed session.

On this page