Files API
Store your Cloud project's files through /v1, charged per stored GB-day./v1/files is your Cloud project’s file store, like S3 or R2: files addressed by a path, kept
until you delete them. Your code, your agents and your sandboxes
share it. Each file’s path is unique in the project, such as reports/2026/q3.pdf; there are no
folders to create, and a prefix like reports/ simply lists the paths that start with it.
Use a developer API key, or the key Dexto gives a deployed Function or Site, with
https://api.dexto.ai. A key only ever sees its own project’s files. A CLI sign-in key gets 403.
Upload a file
Section titled “Upload a file”/v1/files Send the bytes as the body, with their Content-Type and Content-Length. Files up to 80 MiB go
in one request:
curl -X POST "https://api.dexto.ai/v1/files?path=reports/q3.pdf" \ -H "Authorization: Bearer $DEXTO_API_KEY" \ -H "Content-Type: application/pdf" \ --data-binary @q3.pdf| Query or header | Default | Notes |
|---|---|---|
path | Required. 1-1,024 bytes, no leading or trailing /, .. or \. | |
overwrite | false | true replaces the file at path; otherwise a taken path is 409. |
expires_at | ISO 8601 time to delete the file at. | |
X-Content-SHA256 | Lowercase hex SHA-256; the upload is refused when the bytes differ. |
The response is the file, 201 when it was created and 200 when it replaced one:
{ "object": "file", "id": "3a0f8c2e-…", "path": "reports/q3.pdf", "size_bytes": 482113, "content_type": "application/pdf", "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "metadata": {}, "expires_at": null, "created_by": { "api_key_id": "c41e…", "agent_id": null, "user_id": "8d2a…" }, "created_at": "2026-10-14T18:20:11.000Z", "updated_at": "2026-10-14T18:20:11.000Z"}created_by names the key or agent that wrote the file first, each null once deleted, and the
person who wrote it with their key or an OAuth token, null for agents and deployed code.
Upload a large file in parts
Section titled “Upload a large file in parts”Files up to 5 GiB use an upload session. Start it with the file’s size and SHA-256:
/v1/files/uploads curl -X POST https://api.dexto.ai/v1/files/uploads \ -H "Authorization: Bearer $DEXTO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"path":"data/events.parquet","size_bytes":104857600,"sha256":"<hex>","content_type":"application/octet-stream"}'The session has a part_size_bytes (16 MiB), a part_count and an upload_url. PUT each part
to <upload_url>/<part_number>, starting at 1; every part but the last is exactly
part_size_bytes. The upload URL works without an API key until the session expires a day later,
so you can hand it to a client. Upload a part again to replace it; GET /v1/files/uploads/{id}
lists the parts received so far.
curl -X PUT "$UPLOAD_URL/1" --data-binary @part-1Then complete it. Dexto assembles the parts and checks them against size_bytes and sha256;
when they differ, the upload is discarded and the request answers 400.
/v1/files/uploads/{upload_id}/complete POST /v1/files/uploads/{upload_id}/abort abandons a session and its parts.
List, read and download
Section titled “List, read and download”/v1/files GET /v1/files?prefix=reports/&limit=100 lists files in path order. contains keeps paths that
contain a string, ignoring case. When has_more is true, pass next_after as after for the
next page. The older next_cursor carries the same value and is deprecated.
GET /v1/files/{file_id} reads a file’s metadata and GET /v1/files/{file_id}/content downloads
its bytes.
Share a file with a signed URL
Section titled “Share a file with a signed URL”/v1/files/{file_id}/url curl -X POST "https://api.dexto.ai/v1/files/$FILE_ID/url" \ -H "Authorization: Bearer $DEXTO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"expires_in":3600}'Anyone with the returned url can download the file, without an API key, until expires_at. URLs
last an hour by default and at most a day. Overwriting or deleting the file ends them. Files are
never public otherwise; host public pages with Sites.
Update and delete
Section titled “Update and delete”POST /v1/files/{file_id} changes metadata (up to 32 string entries and 4,096 bytes, replacing
the old metadata), content_type or expires_at (null keeps the file until deleted).
DELETE /v1/files/{file_id} deletes the file and its bytes.
Use files from agents and sandboxes
Section titled “Use files from agents and sandboxes”Give an agent a files tool to find, read, search, write, edit,
delete and share files under a prefix. A running sandbox copies files in
with POST /v1/sandboxes/{id}/files/import and saves its files with /files/export.
A media generation started with save_to saves its
outputs as files; each resource of the generation names its file_id and the file_path it was
saved at.
Pricing and errors
Section titled “Pricing and errors”Stored files are charged once a day to the project, at Cloudflare R2’s storage price plus 25%: $0.000625 per GB a day, about $0.019 per GB a month. Uploads are checked against your credits and spend limits before any byte is accepted. Listing, reading, downloading, signed URLs, deleting and sandbox copies are free.
| Status | Code | When |
|---|---|---|
400 | validation_failed | An invalid path or field, or bytes that differ from SHA-256. |
402 | insufficient_credits | The organization’s credits do not cover the upload. |
402 | spend_limit_reached | The project or key reached its monthly spend limit. |
403 | forbidden | The key is not a developer key or a deployed key. |
404 | not_found | No such file or upload in the key’s project. |
409 | conflict | The path is taken, or the upload is missing parts. |
413 | payload_too_large | A one-request upload over 80 MiB. |
429 | rate_limited | Over 600 reads or 120 writes a minute for the organization. |