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:
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:
| Part | Value | Notes |
|---|---|---|
path | project/folders/name.ext | Optional; the first segment is the project. Requires a key. |
visibility | public, unlisted, or private | Uploads without a key are always unlisted. |
expires_in | A duration such as 24h or 7d | Requires a key. Uploads without a key expire after 24 hours. |
label | Text up to 200 characters | Optional display label. Requires a key. |
content_disposition | inline or attachment | Defaults to inline. |
if_exists | error or replace | What 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:
curl -F file=@report.pdf https://agentfs.cloud/v1/filesThe 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:
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_urlis present:PUTthe whole file there in one request.transport: "s3"withoutupload_url: fetch part URLs withGET /v1/uploads/:id/part-urls?from=1&to=100andPUTeach part to its URL.transport: "worker":PUTeach 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:
curl -sS -X PUT "$UPLOAD_URL" \
-H "Content-Length: 50000000" \
--data-binary @video.mp4Storage 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.
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:
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-001Every 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.
AgentFS