Skip to content
Heimdallm
Marketplace/Documentation
Documentation · Guides

Documents & files

A model reads a document when the request carries it. There are two ways to carry one: put the bytes in the request as a base64 file_data data URL, or store the file once with the Files API and name it by file_id in as many requests as need it. The second saves resending the same megabytes, and it behaves exactly like the first once the request is routed.

Store the file

curl https://api-staging.heimdallm.com/api/v1/files \
-H "Authorization: Bearer $HEIMDALL_API_KEY" \
-F "file=@handbook.pdf"

The answer carries the file's id, its mime_type and its expires_at. A file expires 48 hours after it is stored; after that every request that names it is answered 404, the same as for a file you deleted. Store the file again when a job outlives it.

Name it in a request

A chat completion takes the id in a file part, where the document would otherwise be file_data:

{
  "model": "deepseek/deepseek-v4-flash-0731-abliterated",
  "messages": [
    {
      "role": "user",
      "content": [
        { "type": "text", "text": "Summarize the leave policy in this handbook." },
        { "type": "file", "file": { "file_id": "file_2f1c4a7e9b0d46538a1c7e5f3b204d61" } }
      ]
    }
  ]
}

The other two request dialects name it the way their own wire does:

RouteWhere the id goes
/chat/completions{ "type": "file", "file": { "file_id": "…" } } in a message's content array.
/responses{ "type": "input_file", "file_id": "…" } in a message's content, or in a tool output.
/messages{ "type": "document", "source": { "type": "file", "file_id": "…" } } in a user turn.

The id is the marketplace's own: an id from another service names nothing here and is answered 404. A part names its document one way, so file_id beside file_data is a 400. A filename on the part is kept; without one the stored filename is used.

What the model is sent

The marketplace reads the file under your account before it routes the request, and puts its bytes into the request as a data: URL under the type the file was stored as:

{
  "type": "file",
  "file": {
    "filename": "handbook.pdf",
    "file_data": "data:application/pdf;base64,JVBERi0xLjQK…"
  }
}

That is the part an inline document would have been, so everything that holds for an inline document holds here. The id itself is never sent to a provider and nothing is uploaded to one: the bytes travel inside that one request, and what a provider keeps of a request is what its data policy says. The request is billed as the same request with the document inline, by the tokens the model reports. Storing a file costs nothing.

A stored image named by a file part reaches the model as an image (an image_url part with the same data URL), so it is read by a vision model rather than refused by a document one.

Which models can read it

A model that reads documents lists file among its input modalities, and GET /models?input_modalities=file returns those. Each endpoint says more about its own file input: the sources it is handed bytes from, the formats its decoder reads, which are drawn from application/pdf, text/plain, text/markdown, text/html, text/csv and application/json, and the max_content_size_bytes of the largest document it takes.

A stored file carries its bytes inline, with the media type it was stored as, so an endpoint is a candidate only when its declaration admits both and the file's size. An endpoint that fetches documents from a URL and takes no base64 source is skipped, and so is one whose formats leave out the file's type or whose max_content_size_bytes is below the file's size. When no endpoint of the model is left, the request is refused with 503 naming the input, before any provider is called and before anything is billed.

Limits and refusals

StatusWhen
400A file part names both file_id and file_data, or a request names more than 16 stored files.
404The id names no file your account can read: another account's, a deleted file, an expired one, or a malformed id.
413The stored files the request names total more than 32 MiB, counting a file once for each time it is named.
503No endpoint of the model declares a file input that admits the file's source and type, or the keys stored files are encrypted under could not be reached, which is worth retrying.

The 404 is the answer every route gives for a file you cannot read, so an id says nothing about what another account has stored. A file is read once, at the start of the request: a request that began before the deadline finishes with its bytes, and the next one is answered 404.

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