AgentFS

Files

Upload, list, read, delete, and share files through the file system API.

Use /v1/files for file operations and for quick one-request uploads up to 100 MiB. Resumable uploads handle files up to 5 TB.

File object

The API returns this object for a file:

FieldTypeDescription
typestringAlways file.
idstringFile identifier.
namestringThe final path segment.
pathstringThe path without its leading slash.
labelstring or nullOptional display label.
content_typestringStored media type.
content_dispositionstringinline or attachment.
size_bytesintegerStored size in bytes.
sha256string or nullSHA-256 digest when available, as lowercase hexadecimal.
etagstring or nullStorage entity tag. Use it as the If-Match precondition on a replace or a move.
revisionintegerByte generation. A new file starts at 1; each replace adds one.
visibilitystringEffective visibility: public, unlisted, or private.
expires_atstring or nullISO 8601 expiration time.
agent_idstring or nullThe X-Agent-ID sent by the request that created the file.
run_idstring or nullThe X-Run-ID sent by the request that created the file.
urlstring or nullHosted URL for public and unlisted files. null for private files.
markdownstring or nullMarkdown link when url is present.
created_atstringISO 8601 creation time.
updated_atstringISO 8601 update time.

A file with no explicit visibility uses its project's current default_visibility. Public and unlisted files return a hosted URL; private files require a temporary access URL.

Hosted URLs look like https://f.agentfsusercontent.com/f/<id>. Browser-executed content types (text/html, application/xhtml+xml, image/svg+xml, text/xml, and application/xml) are served from a separate, sandboxed origin instead: https://s.agentfsusercontent.com/f/<id>. This applies whatever type the upload declared. Older f.agentfs.cloud and s.agentfs.cloud links keep working: they redirect permanently to the same path on the new host.

Upload a file

POST /v1/files

Store one file in a single request with a key that has write permission on the target path. One request carries up to 100 MiB; send larger files through /v1/uploads.

Request body

Use multipart/form-data, or send the bytes as the raw request body.

Raw body. Send any Content-Type other than multipart/form-data, set Content-Length to the file size, and pass the fields below as query parameters (path, project, prefix, name, if_exists, visibility, expires_in, content_disposition, label). The Content-Type header is the file's type; application/octet-stream or a missing header means it is inferred from the name. Raw bodies stream straight through without being buffered, so this is the form to use from SDKs and scripts. With Idempotency-Key, a raw request is fingerprinted by its fields and size rather than its bytes.

raw body
curl -sS -X POST "https://agentfs.cloud/v1/files?path=research/notes.md" \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  -H "Content-Type: text/markdown" \
  --data-binary @notes.md

From a URL. Send application/json with url plus any of the fields below. The server fetches the URL itself and streams the bytes into storage, so nothing passes through your process. The URL must be http or https, must not redirect, must not point at a private or internal host, and may deliver at most 100 MB. content_type overrides what the source reports; name sets the filename when no path is given, defaulting to the last URL segment.

from a URL
curl -sS -X POST https://agentfs.cloud/v1/files \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/report.pdf","project":"research"}'

Form. Use multipart/form-data with the fields below.

FieldTypeRequiredDescription
filefileYesFile bytes.
pathstringNoproject/filename or a nested path. Required for a chosen location; needs an API key.
visibilitystringNopublic, unlisted, or private for authenticated uploads. Uploads without a key may omit it or send unlisted. If omitted for an authenticated upload, the file follows the project's current default visibility.
expires_instring or nullNoDuration such as 24h or 7d using an s, m, h, d, or w suffix, or null. Authenticated values can be at most 52 weeks. Uploads without a key cannot set it and expire after 24 hours. If omitted, a project default may apply; null is accepted but also allows that project default to apply.
content_dispositionstringNoinline or attachment. Defaults to inline.
labelstring or nullNoOptional label, at most 200 characters.
if_existsstringNoerror (the default) or replace. See upsert to a path. replace requires path, so it requires an API key.

Path segments may contain only letters, digits, ., _, and -; paths have at most 16 segments and 2,048 encoded characters. When an authenticated request omits path, use the key's default project when it has one, otherwise default, and generate a sanitized filename with a suffix. Uploads without a key generate a path under guest; see Upload without a key. The content type is inferred from the filename when the uploaded file reports no type or reports application/octet-stream.

Idempotency header

Idempotency-Key is optional and must contain 1–200 characters. A repeated key with the same request returns the existing file. Reusing it for a different request returns idempotency_conflict.

Returns 201 Created and a Location header containing /v1/files/{id}.

Upsert to a path

By default a live file at path returns path_exists. Send if_exists=replace to write over it instead:

Upsert
curl -X POST https://agentfs.cloud/v1/files \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  -F "file=@report.pdf;type=application/pdf" \
  -F "path=reports/report.pdf" \
  -F "if_exists=replace"

The file keeps its ID, path, and hosted URL; revision goes up by one. Only the bytes and the content type change. Visibility, label, and expiry stay as they are, so set them with the upload that created the file. The response is 200 OK with the file object. A create is still 201 Created.

Uploading the same bytes and content type again is a no-op that returns the current file, so a retry is safe.

Send If-Match: <etag> to make the replacement conditional on the file you last read. A mismatch returns 412 precondition_failed and nothing is written.

if_exists=replace needs a path.

Response fields

Returns a file object.

Request

Request
curl -X POST https://agentfs.cloud/v1/files \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  -H "Idempotency-Key: report-2026-03" \
  -F "file=@report.pdf;type=application/pdf" \
  -F "path=reports/report.pdf" \
  -F "visibility=private" \
  -F "expires_in=24h" \
  -F "label=Quarterly report"

Response

201 Created
{
  "type": "file",
  "id": "f_8f2c",
  "name": "report.pdf",
  "path": "reports/report.pdf",
  "label": "Quarterly report",
  "content_type": "application/pdf",
  "content_disposition": "inline",
  "size_bytes": 48213,
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "etag": "etag-report",
  "revision": 1,
  "visibility": "private",
  "expires_at": "2026-03-03T12:00:00.000Z",
  "agent_id": null,
  "run_id": null,
  "url": null,
  "markdown": null,
  "created_at": "2026-03-02T12:00:00.000Z",
  "updated_at": "2026-03-02T12:00:01.000Z"
}

Errors

unauthorized (401), invalid_agent_label (400), invalid_metadata (400), invalid_path (400), api_key_required (401), precondition_failed (412), file_pinned (409), forbidden (403), file_too_large (413), storage_limit_exceeded (413), billing_unavailable (503), quota_exceeded (429), idempotency_conflict (409), path_exists (409), region_unavailable (422), project_create_failed (500), folder_create_failed (500), upload_unavailable (503), upload_failed (502), anonymous_quota_unavailable (503), internal_error (500).

List files

GET /v1/files

List files visible to the API key, ready files by default. Results are ordered newest first, with the file ID breaking ties. The key must have read permission for the requested project or path.

Query parameters

Filters combine. They narrow the list; the key's read scopes are applied separately and always win.

ParameterTypeRequiredDescription
projectstringNoProject name or project ID. Values beginning with p_ are treated as IDs; other values are treated as names.
pathstringNoOne exact path such as reports/2026/final.pdf.
prefixstringNoPath prefix such as reports/2026. Matches that path and everything below it.
qstringNoCase-insensitive text matched against the file name or stored path. search is the same filter under its older name.
searchstringNoAlias of q.
run_idstringNoFiles created by requests that sent this X-Run-ID.
agent_idstringNoFiles created by requests that sent this X-Agent-ID.
statusstringNoComma list of ready, uploading, failed, and trashed. Defaults to ready. Use trashed to find deleted files you can restore.
limitintegerNoNumber of items, from 1 through 200. Defaults to 50.
cursorstringNoOpaque cursor from the previous response.

A filter value must contain 1–200 characters; anything else returns invalid_query.

Combined filters
curl -G "https://agentfs.cloud/v1/files" \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  --data-urlencode "prefix=reports/2026" \
  --data-urlencode "run_id=run-2026-04-01"

Response fields

FieldTypeDescription
itemsarrayFile objects with project and project_id fields added.
items[].projectstringProject name.
items[].project_idstringProject ID.
items[].statusstringready, uploading, failed, or trashed.
next_cursorstring or nullCursor for the next page, or null when there is no next page.

Returns 200 OK.

Request

Request
curl "https://agentfs.cloud/v1/files?project=p_1a2b&limit=50&q=report" \
  -H "Authorization: Bearer $AGENTFS_KEY"

Response

200 OK
{
  "items": [
    {
      "type": "file",
      "id": "f_8f2c",
      "name": "report.pdf",
      "path": "reports/report.pdf",
      "label": "Quarterly report",
      "content_type": "application/pdf",
      "content_disposition": "inline",
      "size_bytes": 48213,
      "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
      "etag": "etag-report",
      "revision": 1,
      "visibility": "public",
      "expires_at": null,
      "agent_id": "research-agent",
      "run_id": "run_2026_03_02",
      "url": "https://f.agentfsusercontent.com/f/f_8f2c",
      "markdown": "[Quarterly report](https://f.agentfsusercontent.com/f/f_8f2c)",
      "created_at": "2026-03-02T12:00:00.000Z",
      "updated_at": "2026-03-02T12:00:01.000Z",
      "project": "reports",
      "project_id": "p_1a2b",
      "status": "ready"
    }
  ],
  "next_cursor": null
}

Errors

unauthorized (401), invalid_agent_label (400), project_not_found (404), forbidden (403), invalid_query (400), internal_error (500).

Get a file

GET /v1/files/:id

Return one ready file with an API key that has read permission on its path.

Path parameters

ParameterTypeRequiredDescription
idstringYesFile ID.

Response fields

Returns a file object.

Returns 200 OK.

Request

Request
curl https://agentfs.cloud/v1/files/f_8f2c \
  -H "Authorization: Bearer $AGENTFS_KEY"

Response

200 OK
{
  "type": "file",
  "id": "f_8f2c",
  "name": "report.pdf",
  "path": "reports/report.pdf",
  "label": "Quarterly report",
  "content_type": "application/pdf",
  "content_disposition": "inline",
  "size_bytes": 48213,
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "etag": "etag-report",
  "revision": 1,
  "visibility": "private",
  "expires_at": "2026-03-03T12:00:00.000Z",
  "agent_id": null,
  "run_id": null,
  "url": null,
  "markdown": null,
  "created_at": "2026-03-02T12:00:00.000Z",
  "updated_at": "2026-03-02T12:00:01.000Z"
}

Errors

unauthorized (401), invalid_agent_label (400), file_not_found (404), forbidden (403), internal_error (500).

Read a file's bytes

GET /v1/files/:id/content

Redirect to the file's bytes. The key needs read permission on the file path. A public or unlisted file redirects to its hosted URL; a private file redirects to a signed URL that is valid for 5 minutes. Use this to read a file you stored without minting a share link first.

Path parameters

ParameterTypeRequiredDescription
idstringYesFile ID.

Response

Returns 302 Found with the URL in Location and an empty body. Follow the redirect with curl -L. If the file was blocked for abuse, the hosted URL answers 451 file_blocked.

302 Found
HTTP/1.1 302 Found
location: https://f.agentfsusercontent.com/f/f_8f2c?expires=1772539200&v=1&signature=example-signature
cache-control: no-store

Request

Request
curl -L https://agentfs.cloud/v1/files/f_8f2c/content \
  -H "Authorization: Bearer $AGENTFS_KEY"

Errors

unauthorized (401), invalid_agent_label (400), file_not_found (404), forbidden (403), internal_error (500).

Delete a file

DELETE /v1/files/:id

Delete a file with an API key that has delete permission on its path, including an unfinished file row.

A delete moves the file to the trash, where it is purged after 30 days; its bytes still count toward your storage until then. Until it is purged, you can restore it. To free the space now, add ?permanent=true: the file is removed for good and cannot be restored. Both forms are safe to repeat. Repeating a permanent delete returns file_not_found (404), because the file is gone.

Path parameters

ParameterTypeRequiredDescription
idstringYesFile ID.

Query parameters

ParameterTypeRequiredDescription
permanenttrueNoDelete for good and free the storage now. Works on a file that is already in the trash.

Response

Returns 204 No Content with an empty body.

204 No Content
HTTP/1.1 204 No Content

Request

Request
curl -X DELETE https://agentfs.cloud/v1/files/f_8f2c \
  -H "Authorization: Bearer $AGENTFS_KEY"

Errors

unauthorized (401), invalid_agent_label (400), file_not_found (404), forbidden (403), storage_unavailable (503), storage_delete_failed (502), internal_error (500).

Restore a file

POST /v1/files/:id/restore

Bring a file back from the trash. It returns to the same path with the same ID and hosted URL. The key needs write permission on the file path.

Restoring a file that is already live returns it again with 200, so a retry is safe. If another live file now holds the path, the response is 409 path_exists: move or delete that file first. A file that was purged, deleted with ?permanent=true, or never existed returns 404 file_not_found.

Path parameters

ParameterTypeRequiredDescription
idstringYesFile ID.

Response

Returns 200 OK with the file object.

Request

Request
curl -X POST https://agentfs.cloud/v1/files/f_8f2c/restore \
  -H "Authorization: Bearer $AGENTFS_KEY"

Errors

unauthorized (401), file_not_found (404), forbidden (403), path_exists (409), internal_error (500).

Create a file access URL

POST /v1/files/:id/access

Return a hosted URL for a file the API key can share. The key must have share permission on the file path.

Public and unlisted files return their existing URL and expires_at: null. Private files get a signed URL that defaults to one hour and may last up to seven days.

Path parameters

ParameterTypeRequiredDescription
idstringYesFile ID.

Request body

Send a JSON object. The body may be empty.

FieldTypeRequiredDescription
expires_instringNoDuration such as 1h or 7d using an s, m, h, d, or w suffix. Used for private files only; the maximum is seven days.

Response fields

FieldTypeDescription
file_idstringFile ID.
urlstringHosted file URL.
markdownstringMarkdown link using the file label or name.
expires_atstring or nullISO 8601 expiration for a private URL, or null for public and unlisted files.

Returns 200 OK.

Request

Request
curl -X POST https://agentfs.cloud/v1/files/f_8f2c/access \
  -H "Authorization: Bearer $AGENTFS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"expires_in":"24h"}'

Response

200 OK
{
  "file_id": "f_8f2c",
  "url": "https://f.agentfsusercontent.com/f/f_8f2c?expires=1772539200&v=1&signature=example-signature",
  "markdown": "[Quarterly report](https://f.agentfsusercontent.com/f/f_8f2c?expires=1772539200&v=1&signature=example-signature)",
  "expires_at": "2026-03-03T12:00:00.000Z"
}

Errors

unauthorized (401), invalid_agent_label (400), file_not_found (404), forbidden (403), invalid_expiration (400), internal_error (500).

POST /v1/files/:id/access/revoke

Invalidate every private link issued for this file so far. Links created before the revoke return 404 from then on; links you create afterwards work as usual. Use it when a private link leaked. The key needs write permission on the file path.

Public and unlisted URLs are not affected. To hide one of those, change the file's visibility or delete it.

Path parameters

ParameterTypeRequiredDescription
idstringYesFile ID.

Response fields

FieldTypeDescription
idstringFile ID.
access_versionintegerThe file's new access version. Private links carry it as v.

Returns 200 OK.

Request

Request
curl -X POST https://agentfs.cloud/v1/files/f_8f2c/access/revoke \
  -H "Authorization: Bearer $AGENTFS_KEY"

Response

200 OK
{
  "id": "f_8f2c",
  "access_version": 2
}

Errors

unauthorized (401), file_not_found (404), forbidden (403), internal_error (500).

On this page