Skip to content
Heimdallm
Marketplace/Documentation
Documentation · API reference

Files API

A file you upload once and refer to by id afterwards, instead of resending the bytes every request. Files belong to the account the key draws from: a file stored with one of your keys is readable with any other key on the same account, and reads as absent to everyone else.

Files are temporary. A file expires 48 hours after it is stored, whether or not anything has read it, and the response states the instant in expires_at. From that instant every route answers 404 for it, exactly as for a file you deleted, and its bytes are removed from the database shortly after. Keep your own copy of anything you need for longer; deleting earlier is always allowed.

The bytes live in the marketplace's database rather than on a gateway's disk. That is what makes a file you upload readable on the next request: the API runs on more than one gateway, and a file written to one machine's disk is a file the next call cannot find. They are stored encrypted, under a key that is kept outside the database and destroyed within 50 hours of the upload, so a backup of the database cannot give a file back after that.

Two limits apply. One file may hold 32 MiB, and one account may hold 512 MiB across every file it has stored and not yet expired. Deleting a file, or its expiry, frees what it held immediately.

POST /files

Stores a file. The body is multipart/form-data with the bytes in a part named file; the part's filename and content type are what the store keeps.

curl https://api-staging.heimdallm.com/api/v1/files \
-H "Authorization: Bearer $HEIMDALL_API_KEY" \
-F "file=@handbook.pdf"
{
  "data": {
    "id": "file_2f1c4a7e9b0d46538a1c7e5f3b204d61",
    "filename": "handbook.pdf",
    "mime_type": "application/pdf",
    "size_bytes": 184320,
    "created_at": "2026-08-16T11:59:31.000Z",
    "expires_at": "2026-08-18T11:59:31.000Z",
    "downloadable": true
  }
}

The accepted types are application/json, application/pdf, image/gif, image/jpeg, image/png, image/webp, text/csv, text/markdown and text/plain. A part sent as application/octet-stream — what a client says when it knows nothing about the file — is typed from its filename extension. Anything else is refused with 400.

The filename comes back in the download's Content-Disposition, so it is kept as a single path segment: directory separators, control characters and quotes are stripped, and the rest is bounded to 200 characters.

GET /files

Every unexpired file on the account, newest first. limit is 1 through 100 and defaults to 20; after is the id the previous page ended on, and next_cursor is null on the last page.

curl "https://api-staging.heimdallm.com/api/v1/files?limit=20" \
-H "Authorization: Bearer $HEIMDALL_API_KEY"
{
  "data": [{ "id": "file_2f1c4a7e9b0d46538a1c7e5f3b204d61", "filename": "handbook.pdf", "…": "…" }],
  "next_cursor": null
}

An after naming no file of your account is refused as an unknown cursor rather than answered with an empty page, so the cursor cannot be used to learn whether an id exists somewhere else. A file that has expired since the previous page was read names no file either, so restart from the first page.

GET /files/:id

The file's metadata, without its content.

curl https://api-staging.heimdallm.com/api/v1/files/file_2f1c4a7e9b0d46538a1c7e5f3b204d61 \
-H "Authorization: Bearer $HEIMDALL_API_KEY"

GET /files/:id/content

The stored bytes, served whole under the type the file was stored as, with the filename in Content-Disposition. Ranges are not offered.

curl https://api-staging.heimdallm.com/api/v1/files/file_2f1c4a7e9b0d46538a1c7e5f3b204d61/content \
-H "Authorization: Bearer $HEIMDALL_API_KEY" \
-o handbook.pdf

DELETE /files/:id

Removes the file and its content, and frees what it held against the quota.

curl -X DELETE https://api-staging.heimdallm.com/api/v1/files/file_2f1c4a7e9b0d46538a1c7e5f3b204d61 \
-H "Authorization: Bearer $HEIMDALL_API_KEY"
{ "data": { "success": true } }

Not idempotent: a second delete answers 404, because a file that is gone and a file that was never stored are the same answer.

Fields

FieldTypeNotes
idstringfile_ followed by 32 hex characters. How every other route addresses it.
filenamestringThe name the upload carried, kept as one path segment.
mime_typestringThe type the content route serves it under.
size_bytesintegerThe stored size, and what the file counts for against the account quota.
created_atstringISO 8601.
expires_atstringISO 8601. When the file stops existing: 48 hours after created_at.
downloadablebooleanThe bytes are held and will be served at /files/:id/content.

Refusals

StatusWhen
400The body was not multipart, carried no file part or an empty one, or named a refused type.
404No such file on your account — the same answer an id another account owns gets, and the one a file past expires_at gets.
409The file would put the account past its quota.
413The file is larger than 32 MiB.
503The keys stored files are encrypted under could not be reached. Retry shortly; the answer says nothing about the file.

A 409 carries metadata.quota_bytes, metadata.used_bytes and metadata.file_bytes, so a client can say exactly how much to free rather than guess.

Using a file in a request

A stored file is named by file_id wherever a request would otherwise carry the document: in a file part on /chat/completions, in an input_file block on /responses, or in a document or image block whose source is { "type": "file", "file_id": "…" } on /messages. The marketplace reads the file under your account when the request arrives, and sends the model's endpoint its bytes as a data: URL, so the endpoint must declare a file input that admits the file's type. An id the account cannot read is the same 404 described above. The Documents & files guide walks through it.

Your files are your data

Files are exported with the rest of your account — metadata and content both, for the files that have not expired — and erased when an account deletion runs; Data & privacy is where both are described, and where the limits of expiry are stated. Nothing about a file reaches a provider by reference: a file part sent upstream carries the bytes the marketplace read for that request.

DiscoverFind your next modelModel libraryAll models, versions, prices and capabilitiesBenchmarksMeasured quality, cost and time by serving configurationShowcaseImages, video and 3D made on the marketplaceProvidersCompare independent inference providersActivityMarketplace traffic and usageNetwork statusAvailability, latency and endpoint healthChatConversations, model settings and filesImage, video & 3DGenerate images, video and 3D assetsScene studioStage a shot in 3D, direct it and render it as a videoCoding playgroundBuild software with an AI agent on a machine of your ownOverview & routingIdentity, workspaces and routing preferencesCredits & billingBalance, deposits, ledger and reserved fundsAPI keysKeys scoped to workspaces, limits and expirationOrganizationsTeams, members and shared workspacesRequest historyRequests, receipts, sandbox sessions and account historyReferralsInvitations and referral earningsPrivacyData settings, exports and deletionDocumentationQuickstart, SDKs, pricing and guidesAPI referenceInteractive endpoint reference