Skip to content
Heimdallm
Marketplace/API reference
Reference

API reference

One OpenAI-compatible API in front of every provider on the marketplace. Point an existing SDK at https://api-staging.heimdallm.com/api/v1 and send a key. The documentation walks through each rail; this page is the whole surface, endpoint by endpoint.

inference

Requests the marketplace routes to a provider and bills per unit consumed. Every one of them needs a key.

post/chat/completionsBearer key

Chat completion

The main inference route. stream: true answers with SSE chunks; the chunk before data: [DONE] carries usage, and honoured beside it, wherever the marketplace finished accounting for the exchange, and a caller that left or a reply the accounting could not close sees no usage chunk at all. An error after the stream has opened arrives as a final chunk with an error member rather than as a status, because the status is already sent. Where the endpoint reports structured deliberation, message.reasoning_details (or, streamed, delta.reasoning_details per chunk) carries it beside the flattened reasoning string: reasoning.text entries with an optional signature, reasoning.summary entries, and reasoning.encrypted entries a provider hands back opaque. Streamed entries share an index; a caller concatenating same-index reasoning.text fragments and taking whichever fragment carries a signature reconstructs the entry a non-streamed reply would have sent whole. The member is absent, never an empty array, wherever the endpoint reported nothing structured. Media a turn generated rides beside the prose: message.images carries each picture as an image_url part whose URL is a data URL, and message.audio carries data, transcript and the endpoint's own id and expires_at, arriving fragment by fragment on delta.audio when streamed. An endpoint that answers in content parts rather than in those members is read the same way, so a reply that drew a picture and said nothing keeps a content of "" rather than becoming a billed reply with nothing in it.

Parameters
NameTypeRequiredDescription
X-OpenRouter-Titlestringin header—

App name recorded on the generation. A non-empty value takes precedence over X-Title.

X-Titlestringin header—

App name when X-OpenRouter-Title is absent or empty.

X-Session-Idstringin header—

An opaque conversation id (up to 256 characters) keying session affinity: requests carrying the same id prefer the endpoint that served the conversation, keeping its prompt cache warm. On /chat/completions the session_id body member outranks prompt_cache_key, which outranks this header. On /responses, prompt_cache_key outranks this header. The resolved id is forwarded to the serving endpoint as x-session-id.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstring—

Model id as author/slug, optionally suffixed :free, :nitro (fastest) or :floor (cheapest) or :exacto (measured tool-call reliability, requiring declared parameters). :online is refused with HTTP 400 because web search plugins are unsupported. provider/slug or provider/author/slug names the model that provider serves under that slug and routes to that provider alone; a catalogue id always takes precedence.

modelsarray<string>—

Fallback list, at most 20. The first id that can be routed serves the request.

messagesarrayRequired

The conversation, at least one message. A user message's content is a string or an array of text, image_url, video_url, audio_url, input_audio and file parts; a *_url part carries either a URL the endpoint fetches or a data: URL carrying the bytes. Each part is routed only to endpoints declaring an input for the modality it needs, in the source and format it carries, and an input_audio part reaches an endpoint that takes audio as audio_url rewritten as a data URL. A file part carries its document inline as file_data, or names one stored with /files as file_id, never both: the marketplace reads the stored bytes into the request before routing, so an endpoint is sent a data URL it declared it accepts and never an id, and a stored image reaches the model as an image_url part. A request may name at most 16 stored files, 32 MiB in all. An assistant message may carry a previous reply's reasoning_details, sent back exactly as received, so a provider that binds it to a signature or holds it encrypted can verify or replay the same sequence.

streamboolean—

Answer with SSE chunks instead of one object.

storeboolean—

false is a storage opt-out: vetted ZDR endpoints satisfy it without a provider parameter. true is unsupported because chat completions are not stored and is rejected with 400.

enable_thinkingboolean—

Enable or disable thinking where the endpoint declares this control. Dynamo endpoints receive it as chat_template_kwargs.enable_thinking only when that nested boolean is declared.

stream_optionsobject—

The final usage chunk does not depend on include_usage. Set include_tool_dispatch: true with stream: true and tools to receive named tool_call_dispatch events from qualified endpoints. This option is consumed by the marketplace and omitted upstream.

temperaturenumber—

Sampling temperature.

0 to 2
top_pnumber—

Nucleus sampling mass in (0, 1]. Zero is rejected with 400, not replaced with a default.

at most 1
top_kinteger—

Sample from the k likeliest tokens; -1 disables the filter where an endpoint declares it.

at least -1
min_pnumber—

Floor on a token's probability relative to the likeliest one; forwarded when the endpoint declares min_p.

0 to 1
top_anumber—

Accepted for compatibility; omitted from the upstream chat body.

0 to 1
frequency_penaltynumber—

Penalise repetition by count.

-2 to 2
presence_penaltynumber—

Penalise tokens already present.

-2 to 2
repetition_penaltynumber—

Multiplicative repetition penalty in (0, 2]; forwarded when the endpoint declares repetition_penalty.

at most 2
seedinteger—

Ask for a reproducible sample where the engine offers one.

stopstring | array<string>—

Up to eight sequences that end the generation.

max_tokensinteger—

Ceiling on generated tokens.

1 to 1048576
max_completion_tokensinteger—

The OpenAI spelling of the same ceiling.

1 to 1048576
logit_biasobject—

Per-token bias in [-100, 100], keyed by token id.

logprobsboolean—

Return log probabilities.

top_logprobsinteger—

How many alternatives per position.

0 to 20
response_formatobject—

{ "type": "text" }, { "type": "json_object" } or { "type": "json_schema", "json_schema": { … } }.

structured_outputsboolean—

Routing marker: send it to be routed only to endpoints whose schema adherence has been verified.

toolsarray—

Up to 1536 function tools the model may call. Names must match [a-zA-Z0-9_-]{1,128}.

tool_choicestring | object—

none, auto, required, or one named function.

parallel_tool_callsboolean—

Allow more than one call per turn.

reasoningobject—

effort is translated to reasoning_effort when declared by an OpenAI-compatible endpoint; the shorthand takes precedence. max_tokens supplies the Anthropic thinking budget. The object itself is never forwarded.

reasoning_effortstring—

The shorthand for reasoning.effort. A level an endpoint has been shown to refuse is filtered out of routing on its own, and the rest of the declaration stands.

one of none, minimal, low, medium, high, xhigh, max
include_reasoningboolean—

Put reasoning on the reply where the model emits it.

verbositystring—

How much answer to produce.

one of low, medium, high
ninteger—

One choice per request.

1 to 1
userstring—

An opaque end-user identifier, at most 256 characters.

session_idstring—

The conversation this turn belongs to, keying session affinity. Outranks prompt_cache_key and the X-Session-Id header. The resolved id is forwarded to the serving endpoint as x-session-id.

prompt_cache_keystring—

A cache affinity hint used when session_id is absent. Outranks the X-Session-Id header and is carried to the serving endpoint as x-session-id, rather than as a body parameter.

metadataobject—

Opaque members echoed on the generation record.

modalitiesarray<string>—

What the reply may carry. Naming image or audio asks for generated media in message.images or message.audio; absent takes the endpoint's own default, which for a text model is prose.

one of text, image, audio
image_configobject—

How a generated image is drawn: n, resolution, aspect_ratio, size, quality, output_format, background, output_compression and seed — the drawing members of the image contract. A chat turn resolves resolution and aspect_ratio against the endpoint that serves it, exactly as POST /images does.

audioobject—

The voice and container for generated speech, as { "voice": "alloy", "format": "wav" }. Both members are required: an engine asked for audio has to be told what to speak with and what to encode to, and the marketplace picks neither for you.

providerobject—

Provider eligibility, ordering and measured performance preferences.

routestring—

Alias for sort.partition: fallback groups by model; sort orders across models. An explicit provider.sort.partition wins, followed by this alias, then the workspace partition. Other values receive HTTP 400 naming route.

one of fallback, sort
transformsarray<string>—

Prompt transforms. ["middle-out"] asks for middle-out compression against the chosen endpoint's context window, applied after routing has picked that endpoint. The system message, the earliest user turn and the latest turns are kept, messages are dropped from the middle, and a tool call is never separated from its result. usage reports what was actually sent. [] declines compression, and so does an absent member. Any other element receives HTTP 400 naming the element and its value.

one of middle-out
pluginsarray<object>—

The same ask as transforms, written as a plugin. [{ "id": "context-compression" }] asks for middle-out compression, and an entry may carry configuration beside its id, which is accepted and not read. context-compression is the only served id, and any other, web included, receives HTTP 400 naming the id.

usageobject—

Usage accounting. { "include": true } puts usage on the reply, cost included.

Responses
StatusMeaning
200

An OpenAI chat.completion, plus provider and usage.cost in USD. With stream: true the body is text/event-stream instead.

400

The body did not parse, or a parameter is outside the range the API accepts. A file part that names both file_id and file_data, or a request that names more than 16 stored files, is refused too.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family. A file_id the account cannot read answers 404 as well, whether the file is another account's, was deleted or has passed its expires_at.

408

The upstream did not answer within the deadline.

413

The stored files the request names total more than 32 MiB.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503. A request that names a stored file is also refused 503, to be retried, while the key store that stored files are sealed under cannot be reached.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl https://api-staging.heimdallm.com/api/v1/chat/completions \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "model": "deepseek/deepseek-v4-flash-0731-abliterated",    "messages": [{ "role": "user", "content": "Hello" }]  }'
Response
{
  "id": "gen-01J8Z0X2QZ",
  "object": "chat.completion",
  "created": 1785611388,
  "model": "deepseek/deepseek-v4-flash-0731-abliterated",
  "provider": "ImpCC",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 3,
    "total_tokens": 12,
    "cost": 0.0000021
  }
}

post/completionsBearer key

Text completion

The older OpenAI text-completions shape, a prompt in and text out, over the same inference core. With stream: true, SSE frames carry text_completion objects with choices[].text deltas, a final chunk carrying usage and honoured, and [DONE]. Committed failures use the same error chunk as chat.

Parameters
NameTypeRequiredDescription
X-Session-Idstringin header—

An opaque conversation id (up to 256 characters) keying session affinity: requests carrying the same id prefer the endpoint that served the conversation, keeping its prompt cache warm. On /chat/completions the session_id body member outranks prompt_cache_key, which outranks this header. On /responses, prompt_cache_key outranks this header. The resolved id is forwarded to the serving endpoint as x-session-id.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstring—

Model id as author/slug, optionally suffixed :free, :nitro (fastest) or :floor (cheapest) or :exacto (measured tool-call reliability, requiring declared parameters). :online is refused with HTTP 400 because web search plugins are unsupported. provider/slug or provider/author/slug names the model that provider serves under that slug and routes to that provider alone; a catalogue id always takes precedence.

modelsarray<string>—

Fallback list, at most 20. The first id that can be routed serves the request.

promptstringRequired

The text to continue.

streamboolean—

Return text deltas as SSE, ending with usage and [DONE].

temperaturenumber—

Sampling temperature.

0 to 2
top_pnumber—

Nucleus sampling mass in (0, 1]. Zero is rejected with 400, not replaced with a default.

at most 1
top_kinteger—

Sample from the k likeliest tokens; -1 disables the filter where an endpoint declares it.

at least -1
frequency_penaltynumber—

Penalise repetition by count.

-2 to 2
presence_penaltynumber—

Penalise tokens already present.

-2 to 2
repetition_penaltynumber—

Multiplicative repetition penalty in (0, 2]; forwarded when the endpoint declares repetition_penalty.

at most 2
seedinteger—

Ask for a reproducible sample.

stopstring | array<string>—

Sequences that end the generation.

max_tokensinteger—

Ceiling on generated tokens.

1 to 1048576
logprobsinteger—

How many log probabilities to return per position.

echoboolean—

Repeat the prompt before the completion.

suffixstring—

Text to place after the completion.

userstring—

An opaque end-user identifier.

providerobject—

Provider eligibility, ordering and measured performance preferences.

routestring—

Alias for sort.partition: fallback groups by model; sort orders across models. An explicit provider.sort.partition wins, followed by this alias, then the workspace partition. Other values receive HTTP 400 naming route.

one of fallback, sort
Responses
StatusMeaning
200

An OpenAI text_completion, plus provider and usage.cost.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/completions \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "model": "deepseek/deepseek-v4-flash-0731-abliterated",  "prompt": "The capital of France is",  "max_tokens": 8}'
Response
{
  "id": "gen-01J8Z0X2QZ",
  "object": "text_completion",
  "created": 1785611388,
  "model": "deepseek/deepseek-v4-flash-0731-abliterated",
  "provider": "ImpCC",
  "choices": [
    {
      "index": 0,
      "text": " Paris.",
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 6,
    "completion_tokens": 3,
    "total_tokens": 9,
    "cost": 0.0000016
  }
}

post/messagesBearer key

Anthropic message

The Anthropic Messages dialect over the same inference core: an Anthropic /v1/messages request in, an Anthropic message out — or, with stream: true, a text/event-stream of message_start, content_block_*, message_delta and message_stop events. model is a marketplace model id, as on /chat/completions; a client points ANTHROPIC_BASE_URL at this API and sets ANTHROPIC_MODEL to one. The Anthropic wire carries no conversation id of its own, so X-Session-Id is the only way a client using this dialect takes part in session affinity. The marketplace runs no web search: a tools entry that declares Anthropic's hosted search by a dated type (web_search_20250305 and later versions) is refused, and a reply never carries server_tool_use or web_search_tool_result blocks, citations or usage.server_tool_use. A search a client performs is its own function tool, and each call the model makes to it is one tool_use block.

Parameters
NameTypeRequiredDescription
X-Session-Idstringin header—

An opaque conversation id (up to 256 characters) keying session affinity: requests carrying the same id prefer the endpoint that served the conversation, keeping its prompt cache warm. On /chat/completions the session_id body member outranks prompt_cache_key, which outranks this header. On /responses, prompt_cache_key outranks this header. The resolved id is forwarded to the serving endpoint as x-session-id.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelsarray<string>—

Fallback list, at most 20. The first id that can be routed serves the request.

providerobject—

Provider eligibility, ordering and measured performance preferences.

routestring—

Alias for sort.partition: fallback groups by model; sort orders across models. An explicit provider.sort.partition wins, followed by this alias, then the workspace partition. Other values receive HTTP 400 naming route.

one of fallback, sort
transformsarray<string>—

Prompt transforms. ["middle-out"] asks for middle-out compression against the chosen endpoint's context window, applied after routing has picked that endpoint. The system message, the earliest user turn and the latest turns are kept, messages are dropped from the middle, and a tool call is never separated from its result. usage reports what was actually sent. [] declines compression, and so does an absent member. Any other element receives HTTP 400 naming the element and its value.

one of middle-out
pluginsarray<object>—

The same ask as transforms, written as a plugin. [{ "id": "context-compression" }] asks for middle-out compression, and an entry may carry configuration beside its id, which is accepted and not read. context-compression is the only served id, and any other, web included, receives HTTP 400 naming the id.

modelstringRequired

A marketplace model id, the same as /chat/completions takes.

messagesarrayRequired

The conversation, at least one message. Each is a user or assistant turn whose content is a string or an array of text, image, tool_use and tool_result blocks. A system turn placed among them is accepted, and its text joins the leading system prompt rather than staying where it sits. An image or document block whose source is { "type": "file", "file_id": "…" } names a file stored with /files, which is read into the request before routing.

max_tokensintegerRequired

Ceiling on generated tokens (required).

at least 1
systemstring | array—

A system prompt, as a string or an array of text blocks. The text of any system turn in messages follows it, a blank line apart, in one leading system message.

metadataobject—

Opaque request metadata; accepted and ignored.

stop_sequencesarray<string>—

Up to eight sequences that end the generation.

streamboolean—

Answer with an Anthropic event stream instead of one object.

temperaturenumber—

Sampling temperature.

0 to 2
top_pnumber—

Nucleus sampling mass.

0 to 1
top_kinteger—

Sample from the k likeliest tokens.

at least 0
toolsarray—

Tools the model may call, each a name, optional description and input_schema. The client runs them: an entry whose type names one of Anthropic's hosted web search versions (web_search_20250305 and later) asks for a search the marketplace does not run and is refused with HTTP 400, while a function the client declares under the name web_search is its own.

tool_choiceobject—

How tools may be used: auto, any, none, or a named tool.

thinkingobject—

Extended-thinking config; accepted and ignored, since a routed model decides for itself.

Responses
StatusMeaning
200

An Anthropic message object, or a text/event-stream of Anthropic events when stream: true. A picture the model generated is an image content block beside the text, its source a base64 one carrying the bytes and their media_type — or a url one where the endpoint answered with a URL of its own. Streamed, the block arrives whole: one content_block_start carrying the picture, then its content_block_stop. The dialect's usage is a required member stating both counts and a client parsing it rejects an object with a member missing, so a count the endpoint never reported is sent as zero and named in usage.heimdall.unreported, which lists every count whose zero nothing measured; a count absent from that list is the endpoint's own figure, and the extension member is absent from a reply whose counts were both reported and names both where no usage document arrived. message_start names both of them, nothing being measured when a stream opens, and the final message_delta carries the verdict, with honoured beside its usage where the request carried members the endpoint's declarations judged. No block of a reply states a search: there is no server_tool_use or web_search_tool_result block, no citation on a text block and no usage.server_tool_use member, because the marketplace ran none, and a client that counts searches from those members counts none.

400

The body did not parse, or a parameter is outside the range the API accepts. A file part that names both file_id and file_data, or a request that names more than 16 stored files, is refused too. A tools entry whose type is a dated hosted web search such as web_search_20250305 is refused before inference, with the entry's position in the message. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

401

The key is missing, unknown, revoked, expired or past its spend limit. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

402

The account has no credit left to cover the request. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family. A file_id the account cannot read answers 404 as well, whether the file is another account's, was deleted or has passed its expires_at. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

408

The upstream did not answer within the deadline. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

413

The stored files the request names total more than 32 MiB. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

422

The reply carried generated audio, which this dialect has no content block for. Ask for the model on /chat/completions, whose message.audio carries it. After a stream has opened the same refusal arrives as an error event.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

500

The marketplace failed to serve the request. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

502

The endpoint that was routed to failed, and no other endpoint could serve the request. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503. A request that names a stored file is also refused 503, to be retried, while the key store that stored files are sealed under cannot be reached. A request with stream: true refused before its stream opened answers in AnthropicErrorEnvelope; every other refusal answers in ErrorEnvelope.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/messages \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "model": "deepseek/deepseek-v4-flash-0731-abliterated",  "max_tokens": 1024,  "messages": [    {      "role": "user",      "content": "Hello"    }  ]}'
Response
{
  "id": "msg_01ABC",
  "type": "message",
  "role": "assistant",
  "model": "deepseek/deepseek-v4-flash-0731-abliterated",
  "content": [
    {
      "type": "text",
      "text": "Hello."
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 9,
    "output_tokens": 3
  }
}

post/messages/count_tokensBearer key

Count message tokens

The input-token count for a would-be Messages request, which the Claude Code CLI reads to decide when to compact a conversation. Estimated from the request text.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstringRequired

A marketplace model id.

messagesarrayRequired

The conversation to count, in the Messages shape.

systemstring | array—

A system prompt, counted alongside the messages.

toolsarray—

Tool definitions, counted alongside the messages.

Responses
StatusMeaning
200

The estimated input token count.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/messages/count_tokens \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "model": "deepseek/deepseek-v4-flash-0731-abliterated",  "messages": [    {      "role": "user",      "content": "Hello"    }  ]}'
Response
{
  "input_tokens": 9
}

post/responsesBearer key

OpenAI response

The OpenAI Responses dialect over the same inference core, for clients that speak /v1/responses — OpenAI's Codex CLI among them. A Responses request in, a response object out, or a text/event-stream of response.* events when stream: true. model is a marketplace model id; send the full conversation in input each turn. Non-null previous_response_id and background: true are refused before inference with HTTP 400 (error.code: 400, error.metadata.error_type: invalid_request); the message names the unsupported member. Omitted/null previous_response_id and omitted/false/null background select stateless foreground execution. parallel_tool_calls is forwarded as the chat member of the same name, an advisory control; response objects report parallel_tool_calls: true as a placeholder. store, include and metadata are accepted without effect; responses are not retained server-side. previous_response_id reaching inference is always null, so it names no conversation to fall back on; prompt_cache_key or X-Session-Id supplies affinity without stored-response chaining.

Parameters
NameTypeRequiredDescription
X-Session-Idstringin header—

An opaque conversation id (up to 256 characters) keying session affinity: requests carrying the same id prefer the endpoint that served the conversation, keeping its prompt cache warm. On /chat/completions the session_id body member outranks prompt_cache_key, which outranks this header. On /responses, prompt_cache_key outranks this header. The resolved id is forwarded to the serving endpoint as x-session-id.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelsarray<string>—

Fallback list, at most 20. The first id that can be routed serves the request.

providerobject—

Provider eligibility, ordering and measured performance preferences.

routestring—

Alias for sort.partition: fallback groups by model; sort orders across models. An explicit provider.sort.partition wins, followed by this alias, then the workspace partition. Other values receive HTTP 400 naming route.

one of fallback, sort
transformsarray<string>—

Prompt transforms. ["middle-out"] asks for middle-out compression against the chosen endpoint's context window, applied after routing has picked that endpoint. The system message, the earliest user turn and the latest turns are kept, messages are dropped from the middle, and a tool call is never separated from its result. usage reports what was actually sent. [] declines compression, and so does an absent member. Any other element receives HTTP 400 naming the element and its value.

one of middle-out
pluginsarray<object>—

The same ask as transforms, written as a plugin. [{ "id": "context-compression" }] asks for middle-out compression, and an entry may carry configuration beside its id, which is accepted and not read. context-compression is the only served id, and any other, web included, receives HTTP 400 naming the id.

modelstringRequired

A marketplace model id, the same as /chat/completions takes.

prompt_cache_keystring—

A cache affinity hint that outranks the X-Session-Id header. The resolved id reaches the serving endpoint as x-session-id.

inputstring | arrayRequired

The conversation: a string, or an array of message, function_call and function_call_output items. An input_file content block carries file_data or file_url, or names a file stored with /files as file_id, which is read into the request before routing.

instructionsstring—

A system prompt, prepended to the conversation.

toolsarray—

Tools the model may call, each a flat { type: "function", name, description, parameters }.

tool_choicestring | object—

How tools may be used: auto, none, required, or a named function.

reasoningobject—

Reasoning config; its effort maps to reasoning_effort.

textobject—

Output shape. format is {"type":"text"} (prose, the default), {"type":"json_object"} (JSON mode, sent as response_format) or {"type":"json_schema","name":…,"schema":…,"strict":…}, which is sent as a json_schema response_format and routed only to endpoints declaring structured_outputs. Any other format.type is refused with HTTP 400 before inference.

streamboolean—

Answer with a response.* event stream instead of one object.

max_output_tokensinteger—

Ceiling on generated tokens.

at least 1
temperaturenumber—

Sampling temperature.

0 to 2
top_pnumber—

Nucleus sampling mass.

0 to 1
parallel_tool_callsboolean | null—

False asks for at most one tool call per turn. Advisory: forwarded where the serving endpoint declares parallel_tool_calls, and otherwise reported unhonoured. Response objects report parallel_tool_calls: true as a placeholder.

previous_response_idnull—

Omit or set to null. A non-null value is refused with HTTP 400 naming previous_response_id; send the full conversation in input.

backgroundboolean | null—

Omit or set to false/null for foreground execution. True is refused with HTTP 400 naming background.

one of false, null
storeboolean | null—

Accepted without effect; responses are not retained server-side.

includearray<string>—

Ignored response-include hints.

metadataobject—

Opaque request metadata; accepted and ignored.

userstring—

Accepted without effect; not forwarded by the Responses translation.

Responses
StatusMeaning
200

An OpenAI response object, or a text/event-stream of response.* events when stream: true. Media the model generated rides in the assistant message as further content parts: an output_image part whose image_url is the picture (a data URL wherever the endpoint handed back bytes), and an output_audio part carrying data, transcript and the endpoint's own id and expires_at. Streamed, a picture is added and done in one pair of response.content_part.* events because it arrives whole, while speech accumulates through response.output_audio.delta and response.output_audio.transcript.delta and is finished by their .done events. The dialect's usage states all three counts and a client parsing it rejects an object with a member missing, so a count the endpoint never reported is sent as zero and named in usage.heimdall.unreported, which lists every member whose zero nothing measured — total_tokens among them wherever one of its terms is missing, a total short a term being unknown rather than smaller. A member absent from that list is the endpoint's own figure; the extension member is absent from a reply whose counts were all reported and names all three where no usage document arrived. response.completed carries the same object under the same rule, with honoured beside its usage where the request carried members the endpoint's declarations judged. The stream commits on its first event or after one keep-alive period, whichever comes first, so a rejection that arrives before either — an unknown model, no eligible endpoint, an engine refusing a member — is an HTTP error status with an error body carrying the public envelope's metadata. A failure after the stream has committed sends an event: error frame — {"type":"error","code":null,"message":"…","param":null}, code and param flat beside type rather than nested under an error member, matching the Responses API's own streamed error event — and then ends on response.failed, whose response.status is failed and whose response.error carries a code (invalid_prompt for a rejected request, rate_limit_exceeded, context_length_exceeded, or server_error for a failure worth retrying) and the same message, which ends with the engine's own diagnostic where one came back.

400

The body did not parse, or a parameter is outside the range the API accepts. A file part that names both file_id and file_data, or a request that names more than 16 stored files, is refused too. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

401

The key is missing, unknown, revoked, expired or past its spend limit. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

402

The account has no credit left to cover the request. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family. A file_id the account cannot read answers 404 as well, whether the file is another account's, was deleted or has passed its expires_at. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

408

The upstream did not answer within the deadline. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

413

The stored files the request names total more than 32 MiB. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

500

The marketplace failed to serve the request. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

502

The endpoint that was routed to failed, and no other endpoint could serve the request. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503. A request that names a stored file is also refused 503, to be retried, while the key store that stored files are sealed under cannot be reached. A request with stream: true refused before its stream opened answers in ResponsesErrorEnvelope, whose code is null; every other refusal answers in ErrorEnvelope.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/responses \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "model": "deepseek/deepseek-v4-flash-0731-abliterated",  "input": [    {      "type": "message",      "role": "user",      "content": [        {          "type": "input_text",          "text": "Hello"        }      ]    }  ]}'
Response
{
  "id": "resp_01ABC",
  "object": "response",
  "status": "completed",
  "model": "deepseek/deepseek-v4-flash-0731-abliterated",
  "output": [
    {
      "id": "resp_01ABC-msg-0",
      "type": "message",
      "status": "completed",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "Hello.",
          "annotations": []
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 9,
    "output_tokens": 3,
    "total_tokens": 12
  }
}

post/embeddingsBearer key

Embeddings

Text, pre-tokenized or multimodal input in, vectors out. An embeddings endpoint never streams, so it publishes no time-to-first-token figure. Media parts route only to endpoints declaring their input modality, source and format; a request with no matching seller receives a no-route response.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstringRequired

Model id as author/slug, optionally suffixed :free, :nitro (fastest) or :floor (cheapest) or :exacto (measured tool-call reliability, requiring declared parameters). :online is refused with HTTP 400 because web search plugins are unsupported. provider/slug or provider/author/slug names the model that provider serves under that slug and routes to that provider alone; a catalogue id always takes precedence.

inputstring | arrayRequired

One text or a batch of them, pre-tokenized integer arrays, or a multimodal batch — items of { content: [...] } whose parts are { type: "text", text }, { type: "image_url", image_url: { url } }, or { type: "input_audio" | "input_video" | "input_file", <same name>: { data, format } } carrying the bytes base64-encoded. A multimodal input is refused on a model whose declared input modalities do not cover the parts it carries. A multimodal model can embed a content item and a plain string in two bases whose vectors are not interchangeable, so an index and the queries run against it use one shape.

input_typestring—

Hint at how the vectors will be used, e.g. search_query, search_document.

encoding_formatstring—

How the vectors come back.

one of float, base64
dimensionsinteger—

Truncate to this many dimensions where the model allows it.

at least 1
userstring—

An opaque end-user identifier.

providerobject—

Provider eligibility, ordering and measured performance preferences.

Responses
StatusMeaning
200

An OpenAI embeddings list, plus id, provider and usage.cost. usage.prompt_tokens_details carries the per-modality share of prompt_tokens (text_tokens, image_tokens, audio_tokens, video_tokens, file_tokens) and is present only when the input mixed modalities and the endpoint reported the split. Unreported token counts are omitted; explicit zeros are retained.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl https://api-staging.heimdallm.com/api/v1/embeddings \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "model": "baai/bge-m3",    "input": "The quick brown fox"  }'
Response
{
  "object": "list",
  "id": "gen-01J8Z0X2QZ",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [
        0.0123,
        -0.0456
      ]
    }
  ],
  "model": "baai/bge-m3",
  "provider": "ImpCC",
  "usage": {
    "prompt_tokens": 5,
    "total_tokens": 5,
    "cost": 1e-7
  }
}

post/rerankBearer key

Rerank

A query and a set of documents in, one relevance score per document out. Routed only to models declaring the rerank output modality: a model with no scoring head has no relevance to report. Results come back ordered by score, highest first, and cut to top_n where one was named. Nothing streams. Billed per token where the endpoint publishes a prompt price and reports a count, and per request where it publishes a request price; an endpoint publishing neither records the units unpriced rather than billing them at zero.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstringRequired

Model id as author/slug, optionally suffixed :free, :nitro (fastest) or :floor (cheapest) or :exacto (measured tool-call reliability, requiring declared parameters). :online is refused with HTTP 400 because web search plugins are unsupported. provider/slug or provider/author/slug names the model that provider serves under that slug and routes to that provider alone; a catalogue id always takes precedence.

querystringRequired

What the documents are scored against.

documentsarray<string | object>Required

The documents to score. Each is a string, or an object carrying text, image, or both for a vision reranker. An image document requires an endpoint declaring image input; if none qualify, routing returns 503 with input_unsupported before calling a provider or reserving credit.

top_ninteger—

How many of the highest-scoring documents come back. Absent returns all of them.

at least 1
return_documentsboolean—

Echo each result's document back beside its score, exactly as it was submitted.

userstring—

An opaque end-user identifier.

providerobject—

Provider eligibility, ordering and measured performance preferences.

Responses
StatusMeaning
200

The ranking, highest score first, plus provider and usage.cost. usage.total_tokens is omitted where the endpoint reported no count. usage.search_units counts one query against up to 100 documents as one unit, ceil(documents / 100), reported for reconciliation against the Cohere search-unit shape rather than as a charge of its own.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/rerank \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "model": "baai/bge-reranker-v2-m3",  "query": "What is the capital of France?",  "documents": [    "Paris is the capital of France.",    "Berlin is the capital of Germany."  ],  "top_n": 1}'
Response
{
  "id": "gen_01J8Z4K6V9",
  "model": "baai/bge-reranker-v2-m3",
  "provider": "ImpCC",
  "results": [
    {
      "index": 0,
      "relevance_score": 0.987
    }
  ],
  "usage": {
    "search_units": 1,
    "total_tokens": 26,
    "cost": 4e-7
  }
}

post/systemoneBearer key

Answer typed decisions

Answer choice, score and noul questions about a supplied state in one inference call. Each question is evaluated against the state. A request that cannot fit an endpoint window is refused rather than truncated.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstringRequired

Model id as author/slug, optionally suffixed :free, :nitro (fastest) or :floor (cheapest) or :exacto (measured tool-call reliability, requiring declared parameters). :online is refused with HTTP 400 because web search plugins are unsupported. provider/slug or provider/author/slug names the model that provider serves under that slug and routes to that provider alone; a catalogue id always takes precedence.

stateanyRequired

The text or structured content judged by every question.

questionsobjectRequired

Questions keyed by caller chosen identifiers; each carries a type, instructions and any criteria.

providerobject—

Provider eligibility, ordering and measured performance preferences.

userstring—

An opaque end-user identifier.

session_idstring—

An opaque session identifier for routing affinity.

traceobject—

Trace metadata accepted by the marketplace and omitted from the upstream request.

Responses
StatusMeaning
200

Typed answers with probabilities and measured input tokens.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/systemone \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "model": "convaiinnovations/laya",  "state": "Refund the duplicate charge.",  "questions": {    "dept": {      "type": "choice",      "instructions": "Which team?",      "criteria": {        "billing": "Invoices and refunds",        "engineering": "Bugs and outages"      }    }  }}'
Response
{
  "id": "gen_01J8Z4K6V9",
  "model": "convaiinnovations/laya",
  "provider": "ImpCC",
  "answers": {
    "dept": {
      "type": "choice",
      "choice": "billing",
      "probabilities": {
        "billing": 0.94,
        "engineering": 0.06
      },
      "confidence": 0.81
    }
  },
  "usage": {
    "input_tokens": 123,
    "output_tokens": 0,
    "cost": 0.0000052
  }
}

post/benchmark/imagesBearer key

Retain an admitted benchmark image artifact

Restricted to the benchmark worker identity and its durable task claim. Requires one buffered image (n=1, stream=false). Ordinary API keys cannot use this operation; use /images for image generation. The response acknowledges private artifact retention and contains no media bytes.

Parameters
NameTypeRequiredDescription
X-Heimdall-Probe-Endpointstringin headerRequired

Endpoint bound to the admitted benchmark task. X-Heimdallm-Probe-Endpoint is read as the same header.

X-Heimdall-Benchmark-Taskstringin headerRequired

Single-use durable benchmark task identifier. X-Heimdallm-Benchmark-Task is read as the same header.

Request bodyapplication/json

The reference Image API request body, parsed by POST /images.

Fields
NameTypeRequiredDescription
modelstringRequired

The image model to use.

promptstringRequired

What to draw.

ninteger—

Upper bound on images returned; an endpoint may return fewer.

1 to 10
resolutionstring—

Resolution tier, resolved against the endpoint's envelope into the pixels it draws.

one of 512, 1K, 2K, 4K
aspect_ratiostring—

Aspect ratio, snapped to the endpoint's own grid at the resolution tier.

one of 1:1, 1:2, 1:4, 1:8, 2:1, 2:3, 2.35:1, 3:2, 3:4, 4:1, 4:3, 4:5, 5:2, 5:4, 8:1, 9:16, 16:9, 9:19.5, 19.5:9, 9:20, 20:9, 9:21, 21:9, auto
sizestring—

A tier or explicit WIDTHxHEIGHT pixels; pixels named beside a tier or a ratio are refused with 400.

qualitystring—

Rendering quality. Ignored by an endpoint with no such knob.

one of auto, low, medium, high, xhigh, max
output_formatstring—

Encoding of the returned bytes. svg is vectorized markup, UTF-8 base64-encoded in b64_json.

one of png, jpeg, webp, svg
backgroundstring—

transparent requires an output_format carrying alpha (png or webp).

one of auto, transparent, opaque
output_compressioninteger—

Compression for webp/jpeg output. Ignored for png.

0 to 100
seedinteger—

Ask for a reproducible render, where the provider supports it.

streamboolean—

Relay the render as it is drawn, where the endpoint declares stream; the rest answer with the completed image alone.

input_referencesarray<any>—

Bounded inline image references. An https: URL parses here and is refused before dispatch: the marketplace fetches nothing on a caller's behalf.

providerany—

Routing preferences, plus per-provider passthrough under options keyed by provider slug.

userstring—

An opaque end-user identifier, folded into a hashed id before it reaches a provider.

Responses
StatusMeaning
200

The paid artifact is retained for scoring.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

Benchmark dispatch is unavailable to this caller.

408

The upstream did not answer within the deadline.

409

The task is not eligible for dispatch.

413

The request body is larger than this route accepts. The inline assets a request carries are bounded by their own decoded-byte budget, which is read only once a body has arrived; a body over the route’s size limit is refused here instead.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/benchmark/images \  -H "Authorization: Bearer $HEIMDALL_API_KEY"

post/benchmark/meshesBearer key

Retain an admitted benchmark mesh artifact

Restricted to the benchmark worker identity and its durable task claim. Retains one original GLB under the five-minute dispatch deadline. Ordinary API keys cannot use this operation; use /meshes for mesh generation.

Parameters
NameTypeRequiredDescription
X-Heimdall-Probe-Endpointstringin headerRequired

Endpoint bound to the admitted benchmark task. X-Heimdallm-Probe-Endpoint is read as the same header.

X-Heimdall-Benchmark-Taskstringin headerRequired

Single-use durable benchmark task identifier. X-Heimdallm-Benchmark-Task is read as the same header.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstringRequired

promptstringRequired

Responses
StatusMeaning
200

The paid artifact is retained for scoring.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

Benchmark dispatch is unavailable to this caller.

408

The upstream did not answer within the deadline.

409

The task is not eligible for dispatch.

413

The request body is larger than this route accepts. The inline assets a request carries are bounded by their own decoded-byte budget, which is read only once a body has arrived; a body over the route’s size limit is refused here instead.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/benchmark/meshes \  -H "Authorization: Bearer $HEIMDALL_API_KEY"

post/benchmark/videosBearer key

Retain an admitted benchmark video artifact

Restricted to the benchmark worker identity and its durable task claim. Retains one original silent MP4 under the five-minute dispatch deadline. Ordinary API keys cannot use this operation; use /videos for video generation.

Parameters
NameTypeRequiredDescription
X-Heimdall-Probe-Endpointstringin headerRequired

Endpoint bound to the admitted benchmark task. X-Heimdallm-Probe-Endpoint is read as the same header.

X-Heimdall-Benchmark-Taskstringin headerRequired

Single-use durable benchmark task identifier. X-Heimdallm-Benchmark-Task is read as the same header.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstringRequired

promptstringRequired

sizestringRequired

one of 512x512
fpsintegerRequired

one of 24
secondsnumberRequired

one of 4.041666666666667
seedintegerRequired

42 to 46
generate_audiobooleanRequired

one of false
Responses
StatusMeaning
200

The paid artifact is retained for scoring.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

Benchmark dispatch is unavailable to this caller.

408

The upstream did not answer within the deadline.

409

The task is not eligible for dispatch.

413

The request body is larger than this route accepts. The inline assets a request carries are bounded by their own decoded-byte budget, which is read only once a body has arrived; a body over the route’s size limit is refused here instead.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/benchmark/videos \  -H "Authorization: Bearer $HEIMDALL_API_KEY"

post/benchmark/speechBearer key

Retain an admitted benchmark speech artifact

Restricted to the benchmark worker identity and its durable task claim. Requires one reference recording and WAVE output. Ordinary API keys cannot use this operation; use /audio/speech for speech synthesis. The response acknowledges private artifact retention and contains no media bytes.

Parameters
NameTypeRequiredDescription
X-Heimdall-Probe-Endpointstringin headerRequired

Endpoint bound to the admitted benchmark task. X-Heimdallm-Probe-Endpoint is read as the same header.

X-Heimdall-Benchmark-Taskstringin headerRequired

Single-use durable benchmark task identifier. X-Heimdallm-Benchmark-Task is read as the same header.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
modelstringRequired

Model id as author/slug, optionally suffixed :free, :nitro (fastest) or :floor (cheapest) or :exacto (measured tool-call reliability, requiring declared parameters). :online is refused with HTTP 400 because web search plugins are unsupported. provider/slug or provider/author/slug names the model that provider serves under that slug and routes to that provider alone; a catalogue id always takes precedence.

inputstringRequired

The text to synthesize. Its length in characters is the unit billed.

voicestring—

A voice an endpoint of the model declares, which GET /speech/models publishes. Absent asks for whichever voice the endpoint defaults to. The reference contract's own names (alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, verse) are accepted wherever an endpoint declares them, and where none does the request resolves to the one voice the model's endpoints offer between them — named back in X-Heimdall-Voice — or answers 400 listing the voices it is served with.

response_formatstring—

The codec the audio comes back in. Absent is mp3.

one of mp3, wav, pcm, opus, flac, aac, mulaw, alaw
speednumber—

Playback rate, honoured only where the endpoint declares a range covering it.

0.25 to 4
seedinteger—

Sampling seed, honoured only where the endpoint declares it.

0 to 2147483647
max_new_tokensinteger—

Generation token limit, honoured only where the endpoint declares it.

1 to 4096
instructionsstring—

Free text steering delivery, where the endpoint honours it.

input_referencesarray<object>—

One voice sample to clone, at most 5 MiB of decoded bytes. Requires declared speech input_references and audio input. The sample takes precedence over voice and is not saved as a voice profile.

userstring—

An opaque end-user identifier.

providerobject—

Provider eligibility, ordering and measured performance preferences.

Responses
StatusMeaning
200

The paid artifact is retained for scoring.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

Benchmark dispatch is unavailable to this caller.

408

The upstream did not answer within the deadline.

409

The task is not eligible for dispatch.

413

The request body is larger than this route accepts. The inline assets a request carries are bounded by their own decoded-byte budget, which is read only once a body has arrived; a body over the route’s size limit is refused here instead.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/benchmark/speech \  -H "Authorization: Bearer $HEIMDALL_API_KEY"

post/imagesBearer key

Image generation, reference contract

The reference Image API: a prompt in, pictures out, streamed where the caller asks for it. Geometry is named as explicit pixels (size), a resolution tier (resolution) or an aspect ratio (aspect_ratio), and resolves against each endpoint's declared image_envelope to the one WIDTHxHEIGHT that endpoint is asked for, held against and billed on. A tier no endpoint of the model draws is refused naming the bound it crossed; pixels named beside a tier or a ratio are two answers to one question and are refused with 400. A value outside the domain an endpoint publishes for a member is refused before dispatch rather than by an upstream 400. input_references are bounded inline images: the marketplace fetches nothing on a caller's behalf, so an https: URL is refused where the caller can still act on it. With stream: true the body is a text/event-stream carrying one JSON object per data: line, and only an endpoint declaring stream relays previews — the rest answer buffered, which reaches the caller as the completed image alone. Billing is all or nothing: the charge is computed once from the images that completed and rides out on the reply or on the last image_generation.completed event. A render that failed, or whose caller left, settles nothing, and the previews already delivered are the caller's to keep.

Request bodyapplication/json

The reference Image API request body, parsed by POST /images.

Fields
NameTypeRequiredDescription
modelstringRequired

The image model to use.

promptstringRequired

What to draw.

ninteger—

Upper bound on images returned; an endpoint may return fewer.

1 to 10
resolutionstring—

Resolution tier, resolved against the endpoint's envelope into the pixels it draws.

one of 512, 1K, 2K, 4K
aspect_ratiostring—

Aspect ratio, snapped to the endpoint's own grid at the resolution tier.

one of 1:1, 1:2, 1:4, 1:8, 2:1, 2:3, 2.35:1, 3:2, 3:4, 4:1, 4:3, 4:5, 5:2, 5:4, 8:1, 9:16, 16:9, 9:19.5, 19.5:9, 9:20, 20:9, 9:21, 21:9, auto
sizestring—

A tier or explicit WIDTHxHEIGHT pixels; pixels named beside a tier or a ratio are refused with 400.

qualitystring—

Rendering quality. Ignored by an endpoint with no such knob.

one of auto, low, medium, high, xhigh, max
output_formatstring—

Encoding of the returned bytes. svg is vectorized markup, UTF-8 base64-encoded in b64_json.

one of png, jpeg, webp, svg
backgroundstring—

transparent requires an output_format carrying alpha (png or webp).

one of auto, transparent, opaque
output_compressioninteger—

Compression for webp/jpeg output. Ignored for png.

0 to 100
seedinteger—

Ask for a reproducible render, where the provider supports it.

streamboolean—

Relay the render as it is drawn, where the endpoint declares stream; the rest answer with the completed image alone.

input_referencesarray<any>—

Bounded inline image references. An https: URL parses here and is refused before dispatch: the marketplace fetches nothing on a caller's behalf.

providerany—

Routing preferences, plus per-provider passthrough under options keyed by provider slug.

userstring—

An opaque end-user identifier, folded into a hashed id before it reaches a provider.

Responses
StatusMeaning
200

The rendered images and what they cost, or the stream that drew them.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

413

The request body is larger than this route accepts. The inline assets a request carries are bounded by their own decoded-byte budget, which is read only once a body has arrived; a body over the route’s size limit is refused here instead.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/images \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "model": "comfy/flux-1-schnell",  "prompt": "A lighthouse in fog",  "resolution": "1K",  "aspect_ratio": "16:9"}'
Response
{
  "created": 1785611388,
  "data": [
    {
      "b64_json": "iVBORw0KGgo…",
      "media_type": "image/png"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "cost": 0.0021
  }
}

post/videosBearer key

Submit a video job

A prompt in, a job back. Rendering a clip takes longer than a request can be held open, so this route answers 202 with { id, polling_url, status } the moment the job is accepted and the work goes on without the connection. GET /videos/{jobId} reports how far it got and GET /videos/{jobId}/content hands back the bytes. prompt is optional because a model that animates a supplied frame is given the picture instead of the words; a model that needs a prompt refuses its absence itself. Geometry has two interchangeable spellings — resolution with aspect_ratio, or size as WIDTHxHEIGHT — and which of them a model serves is published by GET /videos/models rather than guessed at here. frame_images pins a still to one end of the clip, each carrying the frame_type that says which end, because an array of one carries no position that could. input_references conditions the generation without being a frame of it; an image reference is the shape every engine takes, while audio and video references reach only the endpoints declaring them. A supplied asset is inline base64 and nothing else, the rule the still rail is held to: the marketplace fetches nothing on a caller's behalf, so a URL it would have to reach is refused with 400 before a job exists. callback_url must be HTTPS: the notification names a job an API key can read, and a cleartext hop would publish it. Billed per second of delivered video at the endpoint's declared rate, tiered by resolution where it declares a tier; frame area is geometry the request chose and not a quantity anybody is charged for. The clip is deleted 10 minutes after its first delivery, and an undelivered one when the job's window closes, once no response is still reading it, so the marketplace retains nothing past the delivery window.

Request bodyapplication/json

What a caller asks a video job for. model is the only member every request carries; everything else is optional because a model that animates a supplied frame needs no prompt, and geometry has two interchangeable spellings.

Fields
NameTypeRequiredDescription
fpsinteger—

Frames per second, restricted to the serving endpoint’s frame grid.

1 to 240
negative_promptstring—

Content the clip should avoid.

stepsinteger—

Denoising steps, within the endpoint’s declared range.

1 to 100
guidance_scalenumber—

Prompt adherence, within the endpoint’s declared range.

0 to 20
reference_strengthnumber—

How closely to follow the supplied reference.

0.01 to 1
samplerstring—

A sampler the endpoint declares.

schedulerstring—

A scheduler the endpoint declares.

modelstringRequired

The model to render with, as the catalogue spells it.

promptstring—

What the clip should show. Optional: a model that animates a supplied frame takes the picture in place of the words, and one that needs a prompt refuses a request without one.

durationnumber—

Requested clip length in seconds. It is the meter: the bill is the delivered duration at the endpoint’s declared per-second rate.

resolutionstring—

The resolution tier to render at, narrowed per model by supported_resolutions. Where an endpoint prices its tiers separately, this is what selects the rate.

one of 480p, 720p, 768p, 1080p, 1K, 2K, 4K
aspect_ratiostring—

The shape to render at, narrowed per model by supported_aspect_ratios.

one of 16:9, 9:16, 1:1, 4:3, 3:4, 3:2, 2:3, 21:9, 9:21
sizestring—

Exact pixel dimensions as WIDTHxHEIGHT, interchangeable with a resolution tier and an aspect ratio.

seedinteger—

Fixing it makes a generation reproducible on the same endpoint.

generate_audioboolean—

Whether to score a soundtrack into the clip. Omission leaves the choice to the endpoint’s own default. Sound is billed by the same per-second rate as the rest of the clip, so asking for it adds no second charge.

frame_imagesarray<object>—

Images to pin to the first and last frame. The role is on the image rather than on its position in the array, because an array of one carries no position that says which end it is.

input_referencesarray<object>—

Assets that condition the generation without being frames of it, each carrying what it is for as role: reference when absent, or a control pass the render keeps the structure of. An image is never a frame here — a pinned still is a frame_images item, and reaches the endpoint under first_frame or last_frame. A role is admitted per kind, as GET /videos/models lists under supported_reference_roles: a picture or a clip takes any control pass, and a sample takes reference alone. The job is routed only to an endpoint declaring every role the array carries for that kind, and a combination of control passes no endpoint loads together fails it naming the sets that are.

callback_urlstring—

Where to post the job once it reaches a terminal status, so a caller need not poll. HTTPS only: the notification names a job an API key can read, and a cleartext hop would publish it.

providerobject—

Routing preferences, plus the per-slug passthrough carrying an engine’s own knobs. Only the keys GET /videos/models publishes under allowed_passthrough_parameters are forwarded.

Responses
StatusMeaning
202

The job was accepted. status is where it starts and polling_url is where to read it next; neither is a claim that anything has been rendered or charged yet.

400

The body did not parse, a parameter is outside the range the API accepts — a resolution, aspect ratio or frame role outside the contract’s own enum, a size that is not WIDTHxHEIGHT, an asset that is not an inline base64 data URI, or a callback_url that is not HTTPS — or the assets the job names cannot be served as asked. frame_images and input_references are folded into one list before dispatch, so the two together carry at most 3 items and at most 20 MiB of decoded bytes; a job over either bound is refused naming it. A combination of control roles no endpoint of the model loads in one render is refused naming the sets it does serve, which reference_inputs.video.control_sets on GET /models/{author}/{slug}/endpoints lists.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

413

The request body is larger than this route accepts. The inline assets a request carries are bounded by their own decoded-byte budget, which is read only once a body has arrived; a body over the route’s size limit is refused here instead.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

Request
job=$(curl -s https://api-staging.heimdallm.com/api/v1/videos \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "model": "comfy/wan-2-2-t2v",    "prompt": "a paper boat drifting across a rain puddle, neon reflections",    "size": "1280x720",    "duration": 8  }')job_id=$(echo "$job" | jq -r '.id')# Poll until the job reaches a terminal status.while true; do  status=$(curl -s https://api-staging.heimdallm.com/api/v1/videos/$job_id -H "Authorization: Bearer $HEIMDALL_API_KEY")  state=$(echo "$status" | jq -r '.status')  [ "$state" = "pending" ] || [ "$state" = "in_progress" ] || break  sleep 2donecurl -s "https://api-staging.heimdallm.com/api/v1/videos/$job_id/content?index=0" \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -o out.mp4
Response
{
  "id": "vjob_2f1c4a7e9b0d46538a1c7e5f3b204d61",
  "polling_url": "/api/v1/videos/vjob_2f1c4a7e9b0d46538a1c7e5f3b204d61",
  "status": "pending"
}

get/videos/{jobId}Bearer key

Poll a video job

How far a job got. pending is accepted and not yet started, in_progress is rendering, and the other four are terminal: completed produced its clips, which stay fetchable until the job's window closes, or for 10 minutes after their first delivery, failed carries the reason in error, cancelled was stopped before it produced one, and expired is a job whose delivery window closed with nothing fetched from it; a job fetched from, even in part, stays completed after its window closes, with no content left to fetch. A member appears once there is something to say — generation_id once the job has been processed and the generation it bills through exists, unsigned_urls once there is content to fetch, clip_durations_seconds alongside it naming what each clip actually came to, usage once it was charged, which is on completion or on a marketplace failure whose dispatch was charged and never stored its result — so an absent member is a fact not yet established rather than an empty one. usage.cost is null where the units the job consumed carry no declared price: a clip nothing priced is recorded unpriced and flagged, never reported as free. The job row outlives its clip, so a job polled after delivery still answers what it was, and what it cost, with the bytes already gone. fault appears only on a failed job whose failure this platform caused rather than the endpoint, and its absence is the ordinary case: the reason the job carries is the answer an endpoint gave.

Parameters
NameTypeRequiredDescription
jobIdstringin pathRequired

The job id POST /videos returned, of the form vjob_ followed by 32 hex characters.

matches ^vjob_[0-9a-f]{32}$
Responses
StatusMeaning
200

The job as it stands.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such job on the key’s own account. Identical whether the id is unknown, malformed, or names a job another account submitted.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/videos/jobId \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "id": "vjob_2f1c4a7e9b0d46538a1c7e5f3b204d61",
  "polling_url": "/api/v1/videos/vjob_2f1c4a7e9b0d46538a1c7e5f3b204d61",
  "status": "completed",
  "generation_id": "gen-01J8Z0X2QZ",
  "unsigned_urls": [
    "/api/v1/videos/vjob_2f1c4a7e9b0d46538a1c7e5f3b204d61/content?index=0"
  ],
  "clip_durations_seconds": [
    4
  ],
  "usage": {
    "cost": 1.12
  }
}

get/videos/{jobId}/contentBearer key

Download a generated clip

The clip itself, as video/mp4 bytes. index selects which clip of a job that produced several and defaults to the first. A response that starts at the first byte and is written through the last — a whole 200, or a 206 for bytes=0- — is its delivery; a range that starts later is not. Delivery does not remove the clip: it stays readable, whole or by range, for 10 minutes from its first delivery, and a fetch started after that answers 410 — a caller that needs to keep it keeps what this route gave it. Two fetches under way at once both complete. Nothing cuts a response short: the clip is never removed while a response is reading it, so a slow download started inside the window finishes. A download that breaks off leaves the clip in place, and Range: bytes=N- fetches the rest. HEAD reports the length and delivers nothing. A clip never delivered stays readable until its job's window closes, 24 hours from the render finishing; it is then removed, and a job nobody fetched from becomes expired while one fetched from, even in part, stays completed. Between them those two rules are why the job store retains nothing past the delivery window, which is what lets a ZDR-approved provider's video endpoint stay ZDR. A job that has not completed has no content to serve and answers 409, which is a different answer from one whose content is gone.

Parameters
NameTypeRequiredDescription
jobIdstringin pathRequired

The job id POST /videos returned, of the form vjob_ followed by 32 hex characters.

matches ^vjob_[0-9a-f]{32}$
indexintegerin query—

Which clip of a job that returned several. The first one by default.

at least 0, defaults to 0
Rangestringin header—

One byte range, as bytes=first-last, bytes=first- or bytes=-count; the unit is read in any case. A response that starts at the first byte and is written through the last is a delivery, so bytes=0- delivers like a whole fetch and a range starting later never does. Any other form, several ranges included, is ignored and the whole asset is served.

Responses
StatusMeaning
200

The clip, as the container the provider produced it in. The body is the video itself, with no JSON envelope.

206

The requested range of the asset. It is not a delivery and removes nothing.

400

index is not a whole number at or above zero.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such job on the key’s own account, or the job produced no clip at that index.

409

The job has not completed, so there is no content to serve yet.

410

The clip is gone: its grace after delivery ended, or it went undelivered until the job expired.

416

The range starts past the final byte. Content-Range states the asset’s length as bytes */size.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Content-Range

The bytes served, as bytes first-last/size.

Request
curl https://api-staging.heimdallm.com/api/v1/videos/jobId/content \  -H "Authorization: Bearer $HEIMDALL_API_KEY"

post/meshesBearer key

Submit a mesh job

A prompt or a set of views in, a job back. Generating a mesh takes far longer than a request can be held open — sampling a dense surface is minutes of card time, and decimating it to a target is the cheap part — so this route answers 202 with { id, polling_url, status } the moment the job is accepted and the work goes on without the connection. GET /meshes/{jobId} reports how far it got and GET /meshes/{jobId}/content hands back the GLB. One of prompt and input_references has to be present: an ask naming neither builds nothing, and an image-only endpoint refuses a prompt beside a supplied view. A view is sent inline as base64; at most four, because more views are a different rig and a different model. target_faces is a ceiling rather than a target — a decimator lands at or below it — and what an endpoint generates is its mesh_envelope, which GET /meshes/models publishes. generate_texture bakes an image into the same container; leaving it out leaves the choice to the endpoint. callback_url must be HTTPS: the notification names a job an API key can read, and a cleartext hop would publish it. Billed per delivered mesh at the endpoint's declared rate, tiered where it declares a tier; the face count is geometry the request chose and not a quantity anybody is charged for, because generation cost does not scale with it. The asset is deleted 10 minutes after its first delivery, and an undelivered one when the job's window closes, once no response is still reading it, so the marketplace retains nothing past the delivery window.

Request bodyapplication/json

What a caller asks a mesh job for. model is the only member every request carries. One of prompt and input_references has to be present. A provider whose mesh engine cannot combine text and views refuses a request naming both.

Fields
NameTypeRequiredDescription
refinementany—

Optional marketplace Blender repair with a selected vision model. Generation, model calls, and machine time are billed separately.

modelstringRequired

The model to generate with, as the catalogue spells it.

promptstring—

What to build. Optional with a supplied view; an image-only engine refuses text alongside a view.

target_facesinteger—

The most faces the mesh may carry, and a ceiling rather than a target: a decimator lands at or below it. Bounded here only against a typo; what an endpoint generates is its mesh_envelope, which GET /meshes/models publishes, and a count outside it is an unrouted request.

4 to 20000000
voxel_resolutioninteger—

Shape cascade resolution in voxels along each axis, within the selected endpoint’s declared choices.

512 to 2048
texture_sizeinteger—

Square texture atlas edge in pixels, within the selected endpoint’s declared choices.

64 to 8192
camera_fovnumber—

Horizontal camera field of view in degrees, where the selected endpoint declares it.

1 to 170
generate_textureboolean—

Whether to bake a texture into the mesh. Omission leaves the choice to the endpoint’s own default. A texture is billed by the declared per-mesh rate like the rest of the asset unless the endpoint declares a tier for it, so asking for it adds no second charge.

input_referencesarray<object>—

Views of one object to build from, at most four, because more views are a different rig and a different model. Inline only: the marketplace fetches nothing on this rail, so a URL it accepted would be an ask it could not carry out.

seedinteger—

Fixing it makes a generation reproducible on the same endpoint.

at least 0
negative_promptstring—

What the text-to-image stage should avoid.

stepsinteger—

Sampling steps, within the provider’s declared limits.

1 to 100
guidance_scalenumber—

Conditioning strength, within the selected endpoint’s declared limits.

0 to 20
samplerstring—

A sampling algorithm supported by the selected endpoint.

schedulerstring—

A sampling schedule supported by the selected endpoint.

callback_urlstring—

Where to post the job once it reaches a terminal status, so a caller need not poll. HTTPS only: the notification names a job an API key can read, and a cleartext hop would publish it.

providerobject—

Routing preferences, plus the per-slug passthrough carrying an engine’s own knobs. Only the keys GET /meshes/models publishes under allowed_passthrough_parameters are forwarded.

Responses
StatusMeaning
202

The job was accepted. status is where it starts and polling_url is where to read it next; neither is a claim that anything has been generated or charged yet.

400

The body did not parse, or a parameter is outside the range the API accepts — a request naming neither a prompt nor a view, a target_faces outside the contract’s own bounds, more than four views, or a callback_url that is not HTTPS.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

Request
job=$(curl -s https://api-staging.heimdallm.com/api/v1/meshes \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "model": "comfy/pixal3d",    "prompt": "a worn leather armchair, a studio prop",    "target_faces": 40000,    "generate_texture": true  }')job_id=$(echo "$job" | jq -r '.id')# Poll until the job reaches a terminal status.while true; do  status=$(curl -s https://api-staging.heimdallm.com/api/v1/meshes/$job_id -H "Authorization: Bearer $HEIMDALL_API_KEY")  state=$(echo "$status" | jq -r '.status')  [ "$state" = "pending" ] || [ "$state" = "in_progress" ] || break  sleep 5doneecho "$status" | jq -r '.meshes[0].faces'curl -s "https://api-staging.heimdallm.com/api/v1/meshes/$job_id/content?index=0" \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -o out.glb
Response
{
  "id": "mjob_8d3b06a1f4c7425e9f2a1d5b7c3e0846",
  "polling_url": "/api/v1/meshes/mjob_8d3b06a1f4c7425e9f2a1d5b7c3e0846",
  "status": "pending"
}

get/meshes/{jobId}Bearer key

Poll a mesh job

How far a job got. pending is accepted and not yet started, in_progress is generating, and the other four are terminal: completed produced its assets, which stay fetchable until the job's window closes, or for 10 minutes after their first delivery, failed carries the reason in error, cancelled was stopped before it produced one, and expired is a job whose delivery window closed with nothing fetched from it; a job fetched from, even in part, stays completed after its window closes, with no content left to fetch. A member appears once there is something to say — generation_id once the job has been processed and the generation it bills through exists, unsigned_urls once there is content to fetch, meshes alongside it naming what each asset actually came to, usage once it was charged, which is on completion or on a marketplace failure whose dispatch was charged and never stored its result — so an absent member is a fact not yet established rather than an empty one. Every figure under meshes is read off the GLB itself rather than taken from what the endpoint reported, so a face count here is a measurement and never a claim. usage.cost is null where the units the job consumed carry no declared price: a mesh nothing priced is recorded unpriced and flagged, never reported as free. The job row outlives its asset, so a job polled after delivery still answers what it was, and what it cost, with the bytes already gone. fault appears only on a failed job whose failure this platform caused rather than the endpoint, and its absence is the ordinary case: the reason the job carries is the answer an endpoint gave.

Parameters
NameTypeRequiredDescription
jobIdstringin pathRequired

The job id POST /meshes returned, of the form mjob_ followed by 32 hex characters.

matches ^mjob_[0-9a-f]{32}$
Responses
StatusMeaning
200

The job as it stands.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such job on the key’s own account. Identical whether the id is unknown, malformed, or names a job another account submitted.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/meshes/jobId \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "id": "mjob_8d3b06a1f4c7425e9f2a1d5b7c3e0846",
  "polling_url": "/api/v1/meshes/mjob_8d3b06a1f4c7425e9f2a1d5b7c3e0846",
  "status": "completed",
  "generation_id": "gen-01J8Z0X2QZ",
  "unsigned_urls": [
    "/api/v1/meshes/mjob_8d3b06a1f4c7425e9f2a1d5b7c3e0846/content?index=0"
  ],
  "meshes": [
    {
      "faces": 38412,
      "vertices": 19317,
      "has_texture": true,
      "bounds": {
        "min": [
          -0.5,
          0,
          -0.5
        ],
        "max": [
          0.5,
          0.82,
          0.5
        ]
      }
    }
  ],
  "usage": {
    "cost": 0.4
  }
}

get/meshes/{jobId}/contentBearer key

Download a generated mesh

The mesh itself, as model/gltf-binary bytes, with any baked texture inside the same container. index selects which asset of a job that produced several and defaults to the first. A response that starts at the first byte and is written through the last — a whole 200, or a 206 for bytes=0- — is its delivery; a range that starts later is not. Delivery does not remove the asset: it stays readable, whole or by range, for 10 minutes from its first delivery, and a fetch started after that answers 410 — a caller that needs to keep it keeps what this route gave it. Two fetches under way at once both complete. Nothing cuts a response short: the asset is never removed while a response is reading it, so a slow download started inside the window finishes. A download that breaks off leaves the asset in place, and Range: bytes=N- fetches the rest. HEAD reports the length and delivers nothing. An asset never delivered stays readable until its job's window closes, 24 hours from the generation finishing; it is then removed, and a job nobody fetched from becomes expired while one fetched from, even in part, stays completed. Between them those two rules are why the job store retains nothing past the delivery window, which is what lets a ZDR-approved provider's mesh endpoint stay ZDR. A job that has not completed has no content to serve and answers 409, which is a different answer from one whose content is gone.

Parameters
NameTypeRequiredDescription
jobIdstringin pathRequired

The job id POST /meshes returned, of the form mjob_ followed by 32 hex characters.

matches ^mjob_[0-9a-f]{32}$
indexintegerin query—

Which asset of a job that returned several. The first one by default.

at least 0, defaults to 0
Rangestringin header—

One byte range, as bytes=first-last, bytes=first- or bytes=-count; the unit is read in any case. A response that starts at the first byte and is written through the last is a delivery, so bytes=0- delivers like a whole fetch and a range starting later never does. Any other form, several ranges included, is ignored and the whole asset is served.

Responses
StatusMeaning
200

The mesh, as a binary glTF container. The body is the asset itself, with no JSON envelope.

206

The requested range of the asset. It is not a delivery and removes nothing.

400

index is not a whole number at or above zero.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such job on the key’s own account, or the job produced no mesh at that index.

409

The job has not completed, so there is no content to serve yet.

410

The mesh is gone: its grace after delivery ended, or it went undelivered until the job expired.

416

The range starts past the final byte. Content-Range states the asset’s length as bytes */size.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Content-Range

The bytes served, as bytes first-last/size.

Request
curl https://api-staging.heimdallm.com/api/v1/meshes/jobId/content \  -H "Authorization: Bearer $HEIMDALL_API_KEY"

delete/meshes/{jobId}/refinementBearer key

Stop mesh repair and preserve the generated asset

Requests cancellation of optional marketplace repair. Generation continues if still pending. The original and last validated repair remain downloadable. Poll the job until repair is terminal.

Parameters
NameTypeRequiredDescription
jobIdstringin pathRequired

The job id POST /meshes returned, of the form mjob_ followed by 32 hex characters.

matches ^mjob_[0-9a-f]{32}$
Responses
StatusMeaning
200

Cancellation request recorded.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

Request
curl -X DELETE https://api-staging.heimdallm.com/api/v1/meshes/jobId/refinement \  -H "Authorization: Bearer $HEIMDALL_API_KEY"

get/meshes/refinement/modelsBearer key

List available mesh repair models and machine pricing

Lists live image-input models with tool support when repair is enabled, and the exact USD rate for its medium machine.

Responses
StatusMeaning
200

Deployment availability, exact machine price, and live vision models with tool support.

429

Too many requests

Request
curl https://api-staging.heimdallm.com/api/v1/meshes/refinement/models \  -H "Authorization: Bearer $HEIMDALL_API_KEY"

post/audio/speechBearer key

Speech

Text in, audio bytes out. The body is the recording itself, in the codec response_format named, with no JSON envelope; X-Generation-Id and X-Provider-Name are sent on it as on every other inference route, and the usage is read back from GET /generation. Routed only to endpoints declaring a speech output, and only to ones declaring the voice, the codec and the speed asked for. A voice no endpoint of the model declares is resolved before routing rather than refused outright: where the model's endpoints offer one voice between them — an endpoint offers the voice it spells default, or its sole voice where it declares exactly one — that voice is routed on and named back in X-Heimdall-Voice, and where they offer more than one or none, the request is a 400 listing every voice the model is served with. Substituting further would pick between voices that do not sound alike and bill the caller for the one they did not choose. GET /speech/models publishes those voices ahead of the call. Billed per CHARACTER of input, counted by the marketplace from the request; an endpoint publishing no character price records the characters unpriced rather than billing them at zero. Seconds of audio produced are published as a figure and billed by nothing. A provider that streams its audio has the body relayed as it arrives.

Request bodymultipart/form-data
Responses
StatusMeaning
200

The encoded audio, with the codec's own content type: audio/mpeg for mp3, audio/wav for wav, audio/pcm for pcm, audio/ogg; codecs=opus for opus, audio/flac for flac, audio/aac for aac, audio/basic for mulaw and audio/x-alaw-basic for alaw. No Content-Length: an endpoint that encodes as it decodes has no length to declare.

400

The body did not parse, a parameter is outside the range the API accepts, or voice names a voice no endpoint of the model declares and the model's endpoints offer no single substitute — that error lists the voices the model is served with under metadata.declared_voices.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

X-Heimdallm-Voice

Sent beside X-Heimdall-Voice with the same value; either spelling may be read.

X-Heimdall-Voice

The voice that spoke, sent only where it is not the one voice named. Its absence is not a claim that the asked-for voice spoke: a request naming no voice is served by the endpoint's own default, which the marketplace has no name for.

X-Heimdallm-Unhonoured

Sent beside X-Heimdall-Unhonoured with the same value; either spelling may be read.

X-Heimdall-Unhonoured

Members of the request that did not reach the engine, comma-separated: the verdict every other rail writes into its reply document, on the one rail whose reply is the recording itself. input, voice, response_format, speed and instructions always reach it; anything else is forwarded only where the serving endpoint declares that name in supported_parameters. Absent where nothing was dropped.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/audio/speech \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "model": "openbmb/voxcpm2",  "input": "The sky above the port was the color of television.",  "voice": "alloy",  "response_format": "wav"}'

post/audio/transcriptionsBearer key

Transcription

Audio in, text out, on either of two bodies: multipart/form-data, with the audio as the file part and everything else a form field, capped at 25 MiB; or JSON, with the audio as base64 bytes under input_audio, for an upload over that cap. Billed by exactly one unit per call: seconds of audio for a duration-priced endpoint, tokens for one priced by them. Nothing streams.

Request bodymultipart/form-data

Form fields with the audio in a file part, or JSON with input_audio. Provider-defined multipart fields accept plain text or JSON literals for numbers, booleans, arrays and objects. Quote a numeric-looking string as a JSON string.

Either multipart/form-data — the audio as a file part, every other member a form field, coerced here from the string every field arrives as — or JSON with the audio as base64 bytes under input_audio, for an upload over the multipart route's 25 MB cap.

Fields
NameTypeRequiredDescription
modelstringRequired

Model id as author/slug, optionally suffixed :free, :nitro (fastest) or :floor (cheapest) or :exacto (measured tool-call reliability, requiring declared parameters). :online is refused with HTTP 400 because web search plugins are unsupported. provider/slug or provider/author/slug names the model that provider serves under that slug and routes to that provider alone; a catalogue id always takes precedence.

input_audioobject—

Base64-encoded audio, on the JSON body variant only.

languagestring—

ISO-639-1 code of the spoken language, where known.

promptstring—

Context to bias spelling and punctuation.

response_formatstring—

What the transcript comes back as.

one of json, text, verbose_json
max_completion_tokensinteger—

Transcript generation token limit, where the endpoint declares it.

at least 1
temperaturenumber—

Sampling temperature.

0 to 1
timestamp_granularitiesarray<string>—

Repeat the field as timestamp_granularities[] for each level wanted.

one of segment, word
streamboolean—

Refused on this route: transcriptions do not stream.

providerobject—

Provider eligibility, ordering and measured performance preferences.

Responses
StatusMeaning
200

response_format: verbose_json adds task, duration, language, segments and words (segments and words carry speaker where the endpoint returns diarization). usage.seconds is whole seconds, rounded up from what the endpoint measured, which is the unit a duration price is charged in; duration is that measurement itself and stays fractional. Unreported usage figures are omitted; an explicitly measured zero is retained.

400

The body did not parse, or a parameter is outside the range the API accepts.

401

The key is missing, unknown, revoked, expired or past its spend limit.

402

The account has no credit left to cover the request.

404

No such model. When the id names a family whose base model is not served, metadata.family_variants lists the served ids in that family.

408

The upstream did not answer within the deadline.

413

The audio file is larger than the 25 MiB the multipart body accepts.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

502

The endpoint that was routed to failed, and no other endpoint could serve the request.

503

No live endpoint can serve the request: none is declared for the model, or every one of them was excluded by something the request asked for. A 503 that carries Retry-After and X-Should-Retry: true is the marketplace restarting, and repeating the request is correct. The same restart reaches a stream that has already begun as an in-band error carrying 503.

X-Generation-Id

The id this call is recorded under, set before anything can fail.

X-Provider-Name

The provider that served the request.

Request
curl https://api-staging.heimdallm.com/api/v1/audio/transcriptions \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -F file=@interview.mp3 \  -F model="openai/whisper-large-v3"
Response
{
  "text": "The quick brown fox jumps over the lazy dog.",
  "model": "openai/whisper-large-v3",
  "provider": "ImpCC",
  "usage": {
    "seconds": 4,
    "cost": 0.000008
  }
}

catalogue

What the marketplace serves and how well it is serving it: models, endpoints, providers, measured metrics. No key required.

get/embeddings/modelsNo key required

List embeddings models

Every served model whose output modality includes embeddings, in the GET /models summary shape — no second catalogue authority, that list filtered.

Parameters
NameTypeRequiredDescription
offsetintegerin query—

Records to skip.

at least 0, defaults to 0
limitintegerin query—

Maximum records to return.

1 to 1000, defaults to 500
Responses
StatusMeaning
200

The served embeddings models.

400

offset or limit is outside the range this route accepts.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/embeddings/models
Response
{
  "data": [
    {
      "id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
      "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
      "created": 1785611388,
      "expiration_date": null,
      "description": "A mixture-of-experts model tuned for speed.",
      "context_length": 131072,
      "architecture": {
        "modality": "text->text",
        "input_modalities": [
          "text"
        ],
        "output_modalities": [
          "text"
        ],
        "tokenizer": "DeepSeek",
        "instruct_type": null
      },
      "license": "mit",
      "parameter_count": 305723922366,
      "weights_dtype": "I8",
      "pricing": {
        "prompt": "0.0000001",
        "completion": "0.0000004",
        "request": "0",
        "input_cache_read": "0.000000037",
        "overrides": [
          {
            "min_prompt_tokens": 131071,
            "prompt": "0.0000002"
          }
        ]
      },
      "top_provider": {
        "context_length": 131072,
        "max_completion_tokens": 32768,
        "is_moderated": false
      },
      "per_request_limits": null,
      "supported_parameters": [
        "temperature",
        "top_p",
        "tools",
        "reasoning_effort"
      ],
      "reasoning": {
        "supported_efforts": [
          "high",
          "medium",
          "low",
          "none"
        ],
        "mandatory": false,
        "default_effort": "medium",
        "default_enabled": true,
        "supports_max_tokens": true
      },
      "default_parameters": {
        "temperature": 1,
        "top_p": 1
      },
      "hugging_face": {
        "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
        "read_at": 1793817600,
        "availability": "public",
        "languages": [
          "en",
          "zh"
        ],
        "papers": [
          "2606.19348"
        ],
        "datasets": [
          "HuggingFaceM4/the_cauldron"
        ],
        "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
        "weights_updated_at": 1727283657,
        "downloads": 128473,
        "likes": 941,
        "evaluations": [
          {
            "task": "text-generation",
            "dataset": "HumanEval",
            "metrics": [
              {
                "name": "pass@1",
                "value": 71.3
              }
            ]
          }
        ]
      },
      "family": {
        "id": "deepseek/deepseek-v4-flash-0731",
        "name": "DeepSeek: DeepSeek V4 Flash 0731"
      },
      "author": "deepseek",
      "tags": [
        "abliterated",
        "moe"
      ],
      "endpoint_count": 1,
      "links": {
        "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
      },
      "supported_voices": null,
      "supported_dimensions": null,
      "supported_languages": null
    }
  ]
}

get/images/modelsNo key required

List image models

Every served model with an image output, in the terms the image contract uses: the GET /models summary narrowed to image models, with supported_parameters restated as a typed descriptor per accepted member and a relative endpoints URL for the listing that answers per endpoint. supported_parameters and supports_streaming are the union across the model's live endpoints, which makes them a discovery aid rather than a promise any one endpoint keeps.

Parameters
NameTypeRequiredDescription
offsetintegerin query—

Records to skip.

at least 0, defaults to 0
limitintegerin query—

Maximum records to return.

1 to 1000, defaults to 500
Responses
StatusMeaning
200

The served image models.

400

offset or limit is outside the range this route accepts.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/images/models
Response
{
  "data": [
    {
      "id": "acme/paint-v1",
      "name": "Acme: Paint V1",
      "description": "A diffusion model for stills.",
      "created": 1785611388,
      "architecture": {
        "input_modalities": [
          "text"
        ],
        "output_modalities": [
          "image"
        ]
      },
      "supported_parameters": {
        "n": {
          "type": "range",
          "min": 1,
          "max": 10
        },
        "seed": {
          "type": "boolean"
        },
        "size": {
          "type": "boolean"
        }
      },
      "supports_streaming": false,
      "endpoints": "/api/v1/images/models/acme/paint-v1/endpoints"
    }
  ]
}

get/images/models/{author}/{slug}/endpointsNo key required

An image model's endpoints

Every live endpoint serving one image model: the parameters it accepts as typed descriptors, the provider-specific keys it takes under provider.options[provider_slug], whether it streams natively, and one pricing line per unit it charges for. A line is published only where the endpoint declared a price for that unit — an undeclared unit is unknown, never free, so a short pricing array is a partial declaration rather than a discount. A model served by nothing answers 200 with an empty endpoints array; a model with no image output is not on this route at all and answers 404.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the model id before the slash.

slugstringin pathRequired

The half of the model id after the slash.

Responses
StatusMeaning
200

The model id and its live image endpoints.

404

No such image model.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/images/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints
Response
{
  "id": "acme/paint-v1",
  "endpoints": [
    {
      "provider_name": "Epsilon Render",
      "provider_slug": "epsilon",
      "provider_id": "7d2e9a40-3c5b-4e1f-8a6d-2b9c0f1e4d3a",
      "provider_tag": "epsilon",
      "supported_parameters": {
        "n": {
          "type": "range",
          "min": 1,
          "max": 10
        },
        "seed": {
          "type": "boolean"
        },
        "size": {
          "type": "boolean"
        }
      },
      "allowed_passthrough_parameters": [],
      "supports_streaming": false,
      "pricing": [
        {
          "billable": "output_image",
          "unit": "megapixel",
          "cost_usd": 0.002
        }
      ]
    }
  ]
}

get/videos/modelsNo key required

List video models

Every served model with a video output, in the terms the video contract uses. Each supported_* member is the union of what the model's live endpoints declare, which makes it a discovery aid rather than a promise any one endpoint keeps, and it is null where none of them declares it — undeclared, not empty, because a model whose endpoints publish no duration list is a model whose durations nobody stated rather than one that serves none. pricing_skus publishes the per-second rate under duration_seconds, and the same name suffixed by a resolution for each tier priced separately, so a tiered price is one meter at several rates rather than several units. A listing carrying only suffixed names declares no untiered rate, which is a partial declaration and not a free tier. allowed_passthrough_parameters names the keys an endpoint accepts under provider.options; parameter_offers publishes direct request controls declared by sellers.

Parameters
NameTypeRequiredDescription
offsetintegerin query—

Records to skip.

at least 0, defaults to 0
limitintegerin query—

Maximum records to return.

1 to 1000, defaults to 500
Responses
StatusMeaning
200

The served video models.

400

offset or limit is outside the range this route accepts.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/videos/models
Response
{
  "data": [
    {
      "id": "comfy/wan-2-2-t2v",
      "canonical_slug": "comfy/wan-2-2-t2v",
      "name": "Comfy: Wan 2.2 T2V",
      "created": 1785611388,
      "description": "A diffusion model for short clips.",
      "hugging_face_id": null,
      "supported_resolutions": [
        "480p",
        "720p"
      ],
      "supported_aspect_ratios": [
        "16:9",
        "9:16"
      ],
      "supported_sizes": null,
      "supported_durations": [
        4,
        8
      ],
      "supported_frame_images": [
        "first_frame"
      ],
      "supported_reference_roles": {
        "image": [
          "first_frame"
        ],
        "video": [
          "reference",
          "depth"
        ]
      },
      "generate_audio": false,
      "seed": true,
      "pricing_skus": {
        "duration_seconds_480p": "0.068",
        "duration_seconds_720p": "0.14"
      },
      "allowed_passthrough_parameters": []
    }
  ]
}

get/meshes/modelsNo key required

List mesh models

Every served model with a mesh output, in the terms the mesh contract uses. Each declared member is the union of what the model's live endpoints state, which makes it a discovery aid rather than a promise any one endpoint keeps, and it is null where none of them declares it — undeclared, not empty, because a model whose endpoints publish no texture capability is a model nobody stated it for rather than one that bakes none. mesh_envelope is the widest envelope across those endpoints — the lowest floor and the highest ceiling any of them serves — because a request is routed to whichever endpoint serves it. pricing_skus publishes the per-mesh rate under mesh_output, and the same name suffixed for each condition an endpoint prices separately, so a tiered price is one meter at several rates rather than several units. A listing carrying only suffixed names declares no untiered rate, which is a partial declaration and not a free tier. allowed_passthrough_parameters names the keys an endpoint accepts under provider.options; parameter_offers publishes direct request controls declared by sellers.

Parameters
NameTypeRequiredDescription
offsetintegerin query—

Records to skip.

at least 0, defaults to 0
limitintegerin query—

Maximum records to return.

1 to 1000, defaults to 500
Responses
StatusMeaning
200

The served mesh models.

400

offset or limit is outside the range this route accepts.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/meshes/models
Response
{
  "data": [
    {
      "id": "comfy/pixal3d",
      "canonical_slug": "comfy/pixal3d",
      "name": "Comfy: Pixal3D",
      "created": 1785611388,
      "description": "A latent-set model for single-object meshes.",
      "hugging_face_id": null,
      "mesh_envelope": {
        "max_faces": 150000,
        "min_faces": 4000,
        "texture": true
      },
      "supported_inputs": [
        "text",
        "image"
      ],
      "reference_inputs": {
        "formats": {
          "image": [
            "image/png",
            "image/jpeg"
          ]
        },
        "max_items": 4
      },
      "generate_texture": true,
      "seed": true,
      "pricing_skus": {
        "mesh_output": "0.35"
      },
      "allowed_passthrough_parameters": []
    }
  ]
}

get/speech/modelsNo key required

List speech models

Every served model whose output modality includes speech, in the GET /models summary shape — no second catalogue authority, that list filtered. Each entry carries a speech object holding the union of what its live endpoints declare: the voices, the codecs and the widest speed range. The union is what the marketplace can be asked for somewhere, not what any one endpoint keeps; links.details reaches the endpoints listing, where each endpoint publishes its own speech_envelope. This is the route to read before sending voice, because a client written against the reference contract knows only that contract's own eleven names.

Parameters
NameTypeRequiredDescription
offsetintegerin query—

Records to skip.

at least 0, defaults to 0
limitintegerin query—

Maximum records to return.

1 to 1000, defaults to 500
Responses
StatusMeaning
200

The served speech models.

400

offset or limit is outside the range this route accepts.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/speech/models
Response
{
  "data": [
    {
      "id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
      "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
      "created": 1785611388,
      "expiration_date": null,
      "description": "A mixture-of-experts model tuned for speed.",
      "context_length": 131072,
      "architecture": {
        "modality": "text->text",
        "input_modalities": [
          "text"
        ],
        "output_modalities": [
          "text"
        ],
        "tokenizer": "DeepSeek",
        "instruct_type": null
      },
      "license": "mit",
      "parameter_count": 305723922366,
      "weights_dtype": "I8",
      "pricing": {
        "prompt": "0.0000001",
        "completion": "0.0000004",
        "request": "0",
        "input_cache_read": "0.000000037",
        "overrides": [
          {
            "min_prompt_tokens": 131071,
            "prompt": "0.0000002"
          }
        ]
      },
      "top_provider": {
        "context_length": 131072,
        "max_completion_tokens": 32768,
        "is_moderated": false
      },
      "per_request_limits": null,
      "supported_parameters": [
        "temperature",
        "top_p",
        "tools",
        "reasoning_effort"
      ],
      "reasoning": {
        "supported_efforts": [
          "high",
          "medium",
          "low",
          "none"
        ],
        "mandatory": false,
        "default_effort": "medium",
        "default_enabled": true,
        "supports_max_tokens": true
      },
      "default_parameters": {
        "temperature": 1,
        "top_p": 1
      },
      "hugging_face": {
        "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
        "read_at": 1793817600,
        "availability": "public",
        "languages": [
          "en",
          "zh"
        ],
        "papers": [
          "2606.19348"
        ],
        "datasets": [
          "HuggingFaceM4/the_cauldron"
        ],
        "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
        "weights_updated_at": 1727283657,
        "downloads": 128473,
        "likes": 941,
        "evaluations": [
          {
            "task": "text-generation",
            "dataset": "HumanEval",
            "metrics": [
              {
                "name": "pass@1",
                "value": 71.3
              }
            ]
          }
        ]
      },
      "family": {
        "id": "deepseek/deepseek-v4-flash-0731",
        "name": "DeepSeek: DeepSeek V4 Flash 0731"
      },
      "author": "deepseek",
      "tags": [
        "abliterated",
        "moe"
      ],
      "endpoint_count": 1,
      "links": {
        "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
      },
      "supported_voices": null,
      "supported_dimensions": null,
      "supported_languages": null
    }
  ]
}

get/catalogueNo key required

Read the complete catalogue

Models, families and providers from one consistent database view, bounded to 2 MiB. An ETag identifies the complete JSON representation. If-None-Match avoids transferring an unchanged body. A cached response expires five seconds after publication, in addition to its bounded refresh duration; unavailable refreshes return 503.

Parameters
NameTypeRequiredDescription
If-None-Matchstringin header—

Content validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

The complete public catalogue. Array entries have the corresponding list route shapes.

304

The current representation matches If-None-Match; no response body.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

503

The catalogue is unavailable or exceeds the response size limit.

ETag

Content validator.

Request
curl https://api-staging.heimdallm.com/api/v1/catalogue
Response
{
  "models": [
    {
      "id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
      "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
      "created": 1785611388,
      "expiration_date": null,
      "description": "A mixture-of-experts model tuned for speed.",
      "context_length": 131072,
      "architecture": {
        "modality": "text->text",
        "input_modalities": [
          "text"
        ],
        "output_modalities": [
          "text"
        ],
        "tokenizer": "DeepSeek",
        "instruct_type": null
      },
      "license": "mit",
      "parameter_count": 305723922366,
      "weights_dtype": "I8",
      "pricing": {
        "prompt": "0.0000001",
        "completion": "0.0000004",
        "request": "0",
        "input_cache_read": "0.000000037",
        "overrides": [
          {
            "min_prompt_tokens": 131071,
            "prompt": "0.0000002"
          }
        ]
      },
      "top_provider": {
        "context_length": 131072,
        "max_completion_tokens": 32768,
        "is_moderated": false
      },
      "per_request_limits": null,
      "supported_parameters": [
        "temperature",
        "top_p",
        "tools",
        "reasoning_effort"
      ],
      "reasoning": {
        "supported_efforts": [
          "high",
          "medium",
          "low",
          "none"
        ],
        "mandatory": false,
        "default_effort": "medium",
        "default_enabled": true,
        "supports_max_tokens": true
      },
      "default_parameters": {
        "temperature": 1,
        "top_p": 1
      },
      "hugging_face": {
        "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
        "read_at": 1793817600,
        "availability": "public",
        "languages": [
          "en",
          "zh"
        ],
        "papers": [
          "2606.19348"
        ],
        "datasets": [
          "HuggingFaceM4/the_cauldron"
        ],
        "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
        "weights_updated_at": 1727283657,
        "downloads": 128473,
        "likes": 941,
        "evaluations": [
          {
            "task": "text-generation",
            "dataset": "HumanEval",
            "metrics": [
              {
                "name": "pass@1",
                "value": 71.3
              }
            ]
          }
        ]
      },
      "family": {
        "id": "deepseek/deepseek-v4-flash-0731",
        "name": "DeepSeek: DeepSeek V4 Flash 0731"
      },
      "author": "deepseek",
      "tags": [
        "abliterated",
        "moe"
      ],
      "endpoint_count": 1,
      "links": {
        "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
      },
      "supported_voices": null,
      "supported_dimensions": null,
      "supported_languages": null
    }
  ],
  "families": [],
  "providers": []
}

get/modelsNo key required

List models

Every model with at least one live endpoint, newest first then by id, narrowed by every filter present. pricing is a representative live endpoint's, selected by declared prompt-token price, then completion-token price, then endpoint id, with unknown token prices last; it does not identify the cheapest image or video tariff. The order is stable under the default sort, so stepping offset walks the whole filtered list and a page shorter than limit is the last one. A filter naming a figure this catalogue does not compute (category, arch, distillable, and the six index bounds) is accepted rather than rejected, but a filter the marketplace cannot evaluate cannot be satisfied: the request answers "data": [] with unsupported_filters naming which of these it sent, whatever every other filter present would otherwise have matched — ?context=8192&category=roleplay answers empty, not the models context alone would have kept. unsupported_filters is absent when every filter sent is one this catalogue computes.

Parameters
NameTypeRequiredDescription
familystringin query—

Restrict the list to one family id.

qstringin query—

Case-insensitive substring match against the model id or its display name.

categorystringin query—

Unsupported: this catalogue computes no curated usage category. Reported in unsupported_filters.

supported_parametersstringin query—

Comma-separated parameter names. A model matches when every named parameter is declared by at least one of its live endpoints, not necessarily the same one.

input_modalitiesstringin query—

Comma-separated modalities the model must accept, all of them (text, image, audio, video, file).

output_modalitiesstringin query—

Comma-separated modalities the model must produce, all of them (text, image, video, audio, speech, transcription, embeddings, rerank, decisions, mesh).

contextintegerin query—

Minimum context length in tokens, against the model's own declared window.

at least 0
min_pricestringin query—

Minimum prompt price. At least one live endpoint must price at or above this. A decimal USD-per-million-token string such as "1.50", compared exactly against the endpoint's declared per-token price. Never a float. An endpoint publishing no rate per token satisfies neither bound.

max_pricestringin query—

Maximum prompt price. At least one live endpoint must price at or below this. A decimal USD-per-million-token string such as "1.50", compared exactly against the endpoint's declared per-token price. Never a float. An endpoint publishing no rate per token satisfies neither bound.

min_output_pricestringin query—

Minimum completion price. At least one live endpoint must price at or above this. A decimal USD-per-million-token string such as "1.50", compared exactly against the endpoint's declared per-token price. Never a float. An endpoint publishing no rate per token satisfies neither bound.

max_output_pricestringin query—

Maximum completion price. At least one live endpoint must price at or below this. A decimal USD-per-million-token string such as "1.50", compared exactly against the endpoint's declared per-token price. Never a float. An endpoint publishing no rate per token satisfies neither bound.

providersstringin query—

Comma-separated provider slugs. At least one live endpoint must belong to one of them.

model_authorsstringin query—

Comma-separated authors, matched against the model's own declared author.

zdrstringin query—

true restricts the list to models with at least one endpoint the ZDR fold keeps (see GET /endpoints/zdr). false is accepted and filters nothing.

one of true, false
regionstringin query—

Comma-separated country codes or datacenter regions. At least one live endpoint must declare a matching datacenter.

archstringin query—

Unsupported: this catalogue declares no architecture classification beyond modality. Reported in unsupported_filters.

distillablestringin query—

Unsupported: this catalogue declares no distillation licence flag. Reported in unsupported_filters.

sortstringin query—

Order of the returned list. newest (default) and oldest order by release date; the rest need a computed figure this catalogue has.

one of newest, oldest, price-low-to-high, price-high-to-low, context-high-to-low, defaults to newest
min_age_daysintegerin query—

Minimum age in days since the model's declared release date.

at least 0
max_age_daysintegerin query—

Maximum age in days since the model's declared release date.

at least 0
min_tool_success_ratenumberin query—

Minimum measured tool_call_success_1d, 0-100. At least one live endpoint must clear its sample gate and meet the bound; a null figure matches neither bound.

0 to 100
max_tool_success_ratenumberin query—

Maximum measured tool_call_success_1d, 0-100. At least one live endpoint must clear its sample gate and meet the bound; a null figure matches neither bound.

0 to 100
min_intelligence_indexnumberin query—

Unsupported: this catalogue computes no intelligence index. Reported in unsupported_filters.

max_intelligence_indexnumberin query—

Unsupported: this catalogue computes no intelligence index. Reported in unsupported_filters.

min_coding_indexnumberin query—

Unsupported: this catalogue computes no coding index. Reported in unsupported_filters.

max_coding_indexnumberin query—

Unsupported: this catalogue computes no coding index. Reported in unsupported_filters.

min_agentic_indexnumberin query—

Unsupported: this catalogue computes no agentic index. Reported in unsupported_filters.

max_agentic_indexnumberin query—

Unsupported: this catalogue computes no agentic index. Reported in unsupported_filters.

limitintegerin query—

Page size. Without it the whole list is returned.

1 to 200
offsetintegerin query—

Rows to skip. Valid on its own, without limit.

at least 0, defaults to 0
Responses
StatusMeaning
200

The served catalogue, filtered and paginated.

400

A parameter is missing, repeated, or outside the range or enum this route accepts.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/models
Response
{
  "data": [
    {
      "id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
      "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
      "created": 1785611388,
      "expiration_date": null,
      "description": "A mixture-of-experts model tuned for speed.",
      "context_length": 131072,
      "architecture": {
        "modality": "text->text",
        "input_modalities": [
          "text"
        ],
        "output_modalities": [
          "text"
        ],
        "tokenizer": "DeepSeek",
        "instruct_type": null
      },
      "license": "mit",
      "parameter_count": 305723922366,
      "weights_dtype": "I8",
      "pricing": {
        "prompt": "0.0000001",
        "completion": "0.0000004",
        "request": "0",
        "input_cache_read": "0.000000037",
        "overrides": [
          {
            "min_prompt_tokens": 131071,
            "prompt": "0.0000002"
          }
        ]
      },
      "top_provider": {
        "context_length": 131072,
        "max_completion_tokens": 32768,
        "is_moderated": false
      },
      "per_request_limits": null,
      "supported_parameters": [
        "temperature",
        "top_p",
        "tools",
        "reasoning_effort"
      ],
      "reasoning": {
        "supported_efforts": [
          "high",
          "medium",
          "low",
          "none"
        ],
        "mandatory": false,
        "default_effort": "medium",
        "default_enabled": true,
        "supports_max_tokens": true
      },
      "default_parameters": {
        "temperature": 1,
        "top_p": 1
      },
      "hugging_face": {
        "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
        "read_at": 1793817600,
        "availability": "public",
        "languages": [
          "en",
          "zh"
        ],
        "papers": [
          "2606.19348"
        ],
        "datasets": [
          "HuggingFaceM4/the_cauldron"
        ],
        "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
        "weights_updated_at": 1727283657,
        "downloads": 128473,
        "likes": 941,
        "evaluations": [
          {
            "task": "text-generation",
            "dataset": "HumanEval",
            "metrics": [
              {
                "name": "pass@1",
                "value": 71.3
              }
            ]
          }
        ]
      },
      "family": {
        "id": "deepseek/deepseek-v4-flash-0731",
        "name": "DeepSeek: DeepSeek V4 Flash 0731"
      },
      "author": "deepseek",
      "tags": [
        "abliterated",
        "moe"
      ],
      "endpoint_count": 1,
      "links": {
        "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
      },
      "supported_voices": null,
      "supported_dimensions": null,
      "supported_languages": null
    }
  ]
}

get/models/countNo key required

Count served models

The size of the complete unfiltered model list across all modalities, before pagination.

Responses
StatusMeaning
200

The number of served models.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/models/count
Response
{
  "data": {
    "count": 2
  }
}

get/models/userBearer key

List models for the authenticated account

The complete unfiltered model list GET /models serves, narrowed by the presented key's own account preferences. The one stored preference this route currently reads is the workspace's default ZDR routing preference (provider.zdr's stored default): when it is true, every model with no live endpoint the ZDR fold keeps is omitted. An account with no such preference, or one set to false, sees the same list GET /models serves.

Responses
StatusMeaning
200

The account's own model list.

401

The key is missing, unknown, revoked, expired or past its spend limit.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/models/user \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": [
    {
      "id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
      "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
      "created": 1785611388,
      "expiration_date": null,
      "description": "A mixture-of-experts model tuned for speed.",
      "context_length": 131072,
      "architecture": {
        "modality": "text->text",
        "input_modalities": [
          "text"
        ],
        "output_modalities": [
          "text"
        ],
        "tokenizer": "DeepSeek",
        "instruct_type": null
      },
      "license": "mit",
      "parameter_count": 305723922366,
      "weights_dtype": "I8",
      "pricing": {
        "prompt": "0.0000001",
        "completion": "0.0000004",
        "request": "0",
        "input_cache_read": "0.000000037",
        "overrides": [
          {
            "min_prompt_tokens": 131071,
            "prompt": "0.0000002"
          }
        ]
      },
      "top_provider": {
        "context_length": 131072,
        "max_completion_tokens": 32768,
        "is_moderated": false
      },
      "per_request_limits": null,
      "supported_parameters": [
        "temperature",
        "top_p",
        "tools",
        "reasoning_effort"
      ],
      "reasoning": {
        "supported_efforts": [
          "high",
          "medium",
          "low",
          "none"
        ],
        "mandatory": false,
        "default_effort": "medium",
        "default_enabled": true,
        "supports_max_tokens": true
      },
      "default_parameters": {
        "temperature": 1,
        "top_p": 1
      },
      "hugging_face": {
        "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
        "read_at": 1793817600,
        "availability": "public",
        "languages": [
          "en",
          "zh"
        ],
        "papers": [
          "2606.19348"
        ],
        "datasets": [
          "HuggingFaceM4/the_cauldron"
        ],
        "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
        "weights_updated_at": 1727283657,
        "downloads": 128473,
        "likes": 941,
        "evaluations": [
          {
            "task": "text-generation",
            "dataset": "HumanEval",
            "metrics": [
              {
                "name": "pass@1",
                "value": 71.3
              }
            ]
          }
        ]
      },
      "family": {
        "id": "deepseek/deepseek-v4-flash-0731",
        "name": "DeepSeek: DeepSeek V4 Flash 0731"
      },
      "author": "deepseek",
      "tags": [
        "abliterated",
        "moe"
      ],
      "endpoint_count": 1,
      "links": {
        "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
      },
      "supported_voices": null,
      "supported_dimensions": null,
      "supported_languages": null
    }
  ]
}

get/models/{author}/{slug}No key required

Get a model

One served model, with the same public object as an entry in GET /models. Only active models with a live endpoint belonging to an approved provider are served.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the model id before the slash.

slugstringin pathRequired

The half of the model id after the slash.

Responses
StatusMeaning
200

The served model.

404

No such served model.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated
Response
{
  "data": {
    "id": "deepseek/deepseek-v4-flash-0731-abliterated",
    "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
    "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
    "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
    "created": 1785611388,
    "expiration_date": null,
    "description": "A mixture-of-experts model tuned for speed.",
    "context_length": 131072,
    "architecture": {
      "modality": "text->text",
      "input_modalities": [
        "text"
      ],
      "output_modalities": [
        "text"
      ],
      "tokenizer": "DeepSeek",
      "instruct_type": null
    },
    "license": "mit",
    "parameter_count": 305723922366,
    "weights_dtype": "I8",
    "pricing": {
      "prompt": "0.0000001",
      "completion": "0.0000004",
      "request": "0",
      "input_cache_read": "0.000000037",
      "overrides": [
        {
          "min_prompt_tokens": 131071,
          "prompt": "0.0000002"
        }
      ]
    },
    "top_provider": {
      "context_length": 131072,
      "max_completion_tokens": 32768,
      "is_moderated": false
    },
    "per_request_limits": null,
    "supported_parameters": [
      "temperature",
      "top_p",
      "tools",
      "reasoning_effort"
    ],
    "reasoning": {
      "supported_efforts": [
        "high",
        "medium",
        "low",
        "none"
      ],
      "mandatory": false,
      "default_effort": "medium",
      "default_enabled": true,
      "supports_max_tokens": true
    },
    "default_parameters": {
      "temperature": 1,
      "top_p": 1
    },
    "hugging_face": {
      "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "read_at": 1793817600,
      "availability": "public",
      "languages": [
        "en",
        "zh"
      ],
      "papers": [
        "2606.19348"
      ],
      "datasets": [
        "HuggingFaceM4/the_cauldron"
      ],
      "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
      "weights_updated_at": 1727283657,
      "downloads": 128473,
      "likes": 941,
      "evaluations": [
        {
          "task": "text-generation",
          "dataset": "HumanEval",
          "metrics": [
            {
              "name": "pass@1",
              "value": 71.3
            }
          ]
        }
      ]
    },
    "family": {
      "id": "deepseek/deepseek-v4-flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731"
    },
    "author": "deepseek",
    "tags": [
      "abliterated",
      "moe"
    ],
    "endpoint_count": 1,
    "links": {
      "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
    },
    "supported_voices": null,
    "supported_dimensions": null,
    "supported_languages": null
  }
}

get/model/{author}/{slug}No key required

Get a model

One served model, with the same public object as an entry in GET /models. Only active models with a live endpoint belonging to an approved provider are served.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the model id before the slash.

slugstringin pathRequired

The half of the model id after the slash.

Responses
StatusMeaning
200

The served model.

404

No such served model.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/model/deepseek/deepseek-v4-flash-0731-abliterated
Response
{
  "data": {
    "id": "deepseek/deepseek-v4-flash-0731-abliterated",
    "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
    "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
    "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
    "created": 1785611388,
    "expiration_date": null,
    "description": "A mixture-of-experts model tuned for speed.",
    "context_length": 131072,
    "architecture": {
      "modality": "text->text",
      "input_modalities": [
        "text"
      ],
      "output_modalities": [
        "text"
      ],
      "tokenizer": "DeepSeek",
      "instruct_type": null
    },
    "license": "mit",
    "parameter_count": 305723922366,
    "weights_dtype": "I8",
    "pricing": {
      "prompt": "0.0000001",
      "completion": "0.0000004",
      "request": "0",
      "input_cache_read": "0.000000037",
      "overrides": [
        {
          "min_prompt_tokens": 131071,
          "prompt": "0.0000002"
        }
      ]
    },
    "top_provider": {
      "context_length": 131072,
      "max_completion_tokens": 32768,
      "is_moderated": false
    },
    "per_request_limits": null,
    "supported_parameters": [
      "temperature",
      "top_p",
      "tools",
      "reasoning_effort"
    ],
    "reasoning": {
      "supported_efforts": [
        "high",
        "medium",
        "low",
        "none"
      ],
      "mandatory": false,
      "default_effort": "medium",
      "default_enabled": true,
      "supports_max_tokens": true
    },
    "default_parameters": {
      "temperature": 1,
      "top_p": 1
    },
    "hugging_face": {
      "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "read_at": 1793817600,
      "availability": "public",
      "languages": [
        "en",
        "zh"
      ],
      "papers": [
        "2606.19348"
      ],
      "datasets": [
        "HuggingFaceM4/the_cauldron"
      ],
      "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
      "weights_updated_at": 1727283657,
      "downloads": 128473,
      "likes": 941,
      "evaluations": [
        {
          "task": "text-generation",
          "dataset": "HumanEval",
          "metrics": [
            {
              "name": "pass@1",
              "value": 71.3
            }
          ]
        }
      ]
    },
    "family": {
      "id": "deepseek/deepseek-v4-flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731"
    },
    "author": "deepseek",
    "tags": [
      "abliterated",
      "moe"
    ],
    "endpoint_count": 1,
    "links": {
      "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
    },
    "supported_voices": null,
    "supported_dimensions": null,
    "supported_languages": null
  }
}

get/models/{author}No key required

Retrieve a model (SDK-compatible)

The single percent-encoded path segment the OpenAI Node and Python SDKs request from models.retrieve(id) — models.retrieve("acme/base-1") requests /models/acme%2Fbase-1. Resolved through the same catalogue projection and the same visibility rules as GET /models/{author}/{slug}, and answered as the bare object those SDKs parse (id, created, object: "model", owned_by) rather than the { data: model } envelope that route keeps. owned_by equals author; every other field is the same as the matching entry in GET /models.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The whole model id, percent-encoded as one path segment (author%2Fslug) rather than split across two.

Responses
StatusMeaning
200

The served model, as a bare object.

404

No such served model.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/models/deepseek%2Fdeepseek-v4-flash-0731-abliterated
Response
{
  "id": "deepseek/deepseek-v4-flash-0731-abliterated",
  "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
  "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
  "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
  "created": 1785611388,
  "expiration_date": null,
  "description": "A mixture-of-experts model tuned for speed.",
  "context_length": 131072,
  "architecture": {
    "modality": "text->text",
    "input_modalities": [
      "text"
    ],
    "output_modalities": [
      "text"
    ],
    "tokenizer": "DeepSeek",
    "instruct_type": null
  },
  "license": "mit",
  "parameter_count": 305723922366,
  "weights_dtype": "I8",
  "pricing": {
    "prompt": "0.0000001",
    "completion": "0.0000004",
    "request": "0",
    "input_cache_read": "0.000000037",
    "overrides": [
      {
        "min_prompt_tokens": 131071,
        "prompt": "0.0000002"
      }
    ]
  },
  "top_provider": {
    "context_length": 131072,
    "max_completion_tokens": 32768,
    "is_moderated": false
  },
  "per_request_limits": null,
  "supported_parameters": [
    "temperature",
    "top_p",
    "tools",
    "reasoning_effort"
  ],
  "reasoning": {
    "supported_efforts": [
      "high",
      "medium",
      "low",
      "none"
    ],
    "mandatory": false,
    "default_effort": "medium",
    "default_enabled": true,
    "supports_max_tokens": true
  },
  "default_parameters": {
    "temperature": 1,
    "top_p": 1
  },
  "hugging_face": {
    "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
    "read_at": 1793817600,
    "availability": "public",
    "languages": [
      "en",
      "zh"
    ],
    "papers": [
      "2606.19348"
    ],
    "datasets": [
      "HuggingFaceM4/the_cauldron"
    ],
    "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
    "weights_updated_at": 1727283657,
    "downloads": 128473,
    "likes": 941,
    "evaluations": [
      {
        "task": "text-generation",
        "dataset": "HumanEval",
        "metrics": [
          {
            "name": "pass@1",
            "value": 71.3
          }
        ]
      }
    ]
  },
  "family": {
    "id": "deepseek/deepseek-v4-flash-0731",
    "name": "DeepSeek: DeepSeek V4 Flash 0731"
  },
  "author": "deepseek",
  "tags": [
    "abliterated",
    "moe"
  ],
  "endpoint_count": 1,
  "links": {
    "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
  },
  "supported_voices": null,
  "supported_dimensions": null,
  "supported_languages": null,
  "object": "model",
  "owned_by": "deepseek"
}

get/models/{author}/{slug}/endpointsNo key required

A model and the endpoints serving it

The model with every live endpoint on it, each carrying its declared limits and its measured metrics. uptime_last_5m and uptime_last_30m count success/error attempts under the ten-sample gate. latency_last_30m aliases the 30-minute time-to-first-token percentiles in seconds. throughput_last_30m uses the same observation rules as daily throughput and its own five-stream gate; its descending performance percentiles make p90 the speed 90% of streams meet or exceed. Daily percentiles retain their ascending statistical meaning. Each recent window carries a matching _samples count; uptime_last_1d_samples accompanies daily uptime. supports_tool_choice follows the tools declaration after standing capability verdicts and measured fidelity filtering. supports_voice_cloning is whether the endpoint declares input_references on its speech output modality, and is false on every endpoint whose document declares no reference clip; perf_last_30m_by_workload is null because workload-specific performance is not measured. speech_envelope is what the endpoint declared it speaks — the voices, the codecs and the speed range — and the only voices a speech request routed to it may name; it is null on every endpoint that synthesizes no speech. A measured figure whose window holds fewer samples than its own gate is null, and the gates differ: five for a timing, ten for uptime, twenty for tool-call success, fifty for the runaway rate. A model that exists with nothing serving it answers 200 with "endpoints": []. compliance.zdr is the marketplace's verdict on the provider's zero-data-retention declaration, not the declaration itself: true once the claim passed review, null while it is under review, false when it was denied or declared false, with compliance.zdr_status naming the verdict (pending, approved, denied) wherever a claim stands. refuted_reasoning_efforts lists the currently declared reasoning_effort levels the endpoint's latest per-level check refuted, empty when none is: the declaration in supported_parameters stands, and a request naming a listed level routes past the endpoint until a later check passes. runaway_rate_1d is the percent of the day's long replies that ended still repeating their own tail with nothing having stopped them, and it is the one percentage here a reader wants low — uptime and tool-call success both read better the higher they are. Its denominator is the replies whose text was read — no embedding, transcription or render is in it — carrying at least 256 completion tokens; a reply that stopped of its own accord and a reply that ended by calling a tool are outside the numerator, and so is one the engine's own repetition detector ended, which stays in the denominator. The reading is taken as the reply passes, over a bounded window of its tail, and no reply text is retained. Each gated figure carries the count behind it, published whether or not the figure is — throughput_last_1d_samples, tool_call_success_1d_samples, runaway_rate_1d_samples, and render_timing_samples with render_timing_sizes beside it because the render fit needs distinct geometries as well as renders. A positive count beside a null figure is a window measured below its gate, 0 is a window that held nothing of that kind, and null is an endpoint nothing has been computed for. family is the model's family, the same { id, name } the GET /models summary carries. benchmarks_note is the grading disclosure every score in an endpoint's benchmarks is read under.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the model id before the slash.

slugstringin pathRequired

The half of the model id after the slash.

Responses
StatusMeaning
200

The model shell, its family and its live endpoints.

404

No such model. When the id names a family whose base model is not served, metadata.family and metadata.family_variants name the served ids to redirect to.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints
Response
{
  "data": {
    "id": "deepseek/deepseek-v4-flash-0731-abliterated",
    "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
    "created": 1785611388,
    "description": "A mixture-of-experts model tuned for speed.",
    "architecture": {
      "modality": "text->text",
      "input_modalities": [
        "text"
      ],
      "output_modalities": [
        "text"
      ],
      "tokenizer": "DeepSeek",
      "instruct_type": null
    },
    "family": {
      "id": "deepseek/deepseek-v4-flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731"
    },
    "endpoints": [
      {
        "name": "ImpCC | deepseek/deepseek-v4-flash-0731-abliterated",
        "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
        "model_name": "DeepSeek V4 Flash 0731",
        "provider_name": "ImpCC",
        "provider_slug": "impcc",
        "provider_id": "0b6f3c1e-8d2a-4f7b-9c1d-5e4a3b2c1d0e",
        "tag": "impcc/fp4",
        "context_length": 131072,
        "max_completion_tokens": 32768,
        "max_prompt_tokens": null,
        "quantization": "fp4",
        "supported_parameters": [
          "temperature",
          "tools",
          "reasoning_effort"
        ],
        "input_modalities": [
          "text"
        ],
        "declared_input_modalities": [
          "text"
        ],
        "capability_qualification": [],
        "reference_inputs": {},
        "render_parameters": {},
        "refuted_reasoning_efforts": [],
        "pricing": {
          "prompt": "0.0000001",
          "completion": "0.0000004",
          "input_cache_read": "0.000000037",
          "input_cache_write": "0.000000125",
          "input_cache_write_1h": "0.0000002",
          "overrides": [
            {
              "min_prompt_tokens": 131071,
              "prompt": "0.0000002"
            }
          ],
          "discount": 0.1
        },
        "status": 0,
        "health": "healthy",
        "uptime_last_5m": null,
        "uptime_last_5m_samples": 3,
        "uptime_last_30m": 100,
        "uptime_last_30m_samples": 14,
        "uptime_last_1d_samples": 90,
        "latency_last_30m": {
          "p50": 0.42,
          "p75": 0.55,
          "p90": 0.9,
          "p99": 1.4
        },
        "latency_last_30m_samples": 7,
        "throughput_last_30m": null,
        "throughput_last_30m_samples": 3,
        "perf_last_30m_by_workload": null,
        "supports_tool_choice": true,
        "supports_voice_cloning": false,
        "uptime_last_1d": 99.5,
        "uptime_last_7d": 99.2,
        "ttft_last_30m": {
          "p50": 0.42,
          "p75": 0.55,
          "p90": 0.9,
          "p99": 1.4
        },
        "ttft_last_1d": null,
        "response_last_30m": {
          "p50": 2.61,
          "p75": 3.1,
          "p90": 4,
          "p99": 6.2
        },
        "response_last_1d": null,
        "throughput_last_1d": {
          "p50": 85.1,
          "p75": 92,
          "p90": 98.4,
          "p99": 110.2
        },
        "throughput_last_1d_samples": 214,
        "render_timing": null,
        "render_timing_samples": 0,
        "render_timing_sizes": 0,
        "image_envelope": null,
        "video_envelope": null,
        "mesh_envelope": null,
        "decisions_envelope": null,
        "speech_envelope": null,
        "supports_implicit_caching": false,
        "compliance": {
          "zdr": true,
          "zdr_status": "approved",
          "hipaa": false
        },
        "data_policy": {
          "training": false,
          "retention_days": 0
        },
        "datacenters": [
          {
            "country_code": "CA"
          }
        ],
        "tool_call_success_1d": 98.2,
        "tool_call_success_1d_samples": 340,
        "runaway_rate_1d": 1.4,
        "runaway_rate_1d_samples": 620,
        "benchmarks": [],
        "capacity": {
          "current": 1,
          "total": 4,
          "updated_at": "2026-08-16T11:59:31.000Z"
        }
      }
    ],
    "benchmarks_note": "Scores are measured on this marketplace through the same routing customer traffic takes."
  }
}

get/models/{author}/{slug}/benchmarksNo key required

A model's benchmark scores

Scores from the benchmark bank, which runs as real paid traffic through the same routing customers use. Only datasets the model is eligible for appear, and only where the run holds enough samples to publish. note is the grading disclosure that goes wherever the scores go. Computed at most once a minute per gateway, and served for up to five minutes past that while it is recomputed; Last-Modified states when.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the model id before the slash.

slugstringin pathRequired

The half of the model id after the slash.

If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

The publishable scores.

304

The body is the one If-None-Match names; no response body.

404

No such model.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/benchmarks
Response
{
  "data": [
    {
      "dataset": "gsm8k",
      "score": 0.83,
      "sample_count": 250,
      "grading": "exact match"
    }
  ],
  "note": "Scores are measured on this marketplace through the same routing customer traffic takes."
}

get/models/{author}/{slug}/seriesNo key required

A model's hourly health series

Per live endpoint, sparse ascending hourly buckets: attempt counts, observed time to first token and median output rate, plus the price changes recorded for the endpoint, each carrying one member per unit the change log records. Discrete percentiles, so every figure published was measured. An hour whose traffic never streamed reports null timings rather than zero. Each row names its model_id, the one row shape the family series shares. Computed at most once a minute per gateway, and served for up to five minutes past that while it is recomputed; Last-Modified states when.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the model id before the slash.

slugstringin pathRequired

The half of the model id after the slash.

daysintegerin query—

Days of history, ending now.

1 to 7, defaults to 7
If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

One series per live endpoint.

304

The body is the one If-None-Match names; no response body.

400

days is outside 1 to 7.

404

No such model.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/series
Response
{
  "data": {
    "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
    "window_days": 7,
    "endpoints": [
      {
        "endpoint_id": "5f0c…",
        "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
        "provider_slug": "impcc",
        "provider_id": "0b6f3c1e-8d2a-4f7b-9c1d-5e4a3b2c1d0e",
        "provider_name": "ImpCC",
        "quantization": "fp8",
        "hours": [
          {
            "hour": "2026-08-16T11:00:00.000Z",
            "ok": 118,
            "error": 2,
            "ttft_p50": 0.42,
            "ttft_p90": 0.9,
            "throughput_median": 63.1
          }
        ],
        "prices": [
          {
            "captured_at": "2026-08-10T09:00:00.000Z",
            "prompt": "0.0000001",
            "completion": "0.0000004",
            "cached_prompt": "0.000000037",
            "request": null,
            "image": null,
            "audio": null,
            "character": null
          }
        ]
      }
    ]
  }
}

get/models/{author}/{slug}/activity/seriesNo key required

A model's daily usage

Per UTC day: requests, prompt and completion token sums, image requests with the megapixels they drew, and audio seconds. Every billed request counts, the marketplace's own paid probe traffic included. Counts only, no money. Sparse: a day without traffic has no entry. Computed at most once a minute per gateway, and served for up to five minutes past that while it is recomputed; Last-Modified states when.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the model id before the slash.

slugstringin pathRequired

The half of the model id after the slash.

daysintegerin query—

Days of history, ending today.

1 to 30, defaults to 30
If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

The daily counts.

304

The body is the one If-None-Match names; no response body.

400

days is outside 1 to 30.

404

No such model.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/activity/series
Response
{
  "data": {
    "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
    "window_days": 30,
    "daily": [
      {
        "date": "2026-08-16",
        "requests": 12,
        "prompt_tokens": 90210,
        "completion_tokens": 4821,
        "images": 0,
        "megapixels": 0,
        "audio_seconds": 0
      }
    ]
  }
}

get/familiesNo key required

List families

A family is one base model and the variants published from it, which is what lets a page offer a quantisation or an abliteration as a choice rather than as a separate model.

Responses
StatusMeaning
200

Every family with a served model in it.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/families
Response
{
  "data": [
    {
      "id": "deepseek/deepseek-v4-flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731",
      "author": "deepseek",
      "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "models": [
        "deepseek/deepseek-v4-flash-0731-abliterated"
      ],
      "endpoint_count": 3,
      "providers": [
        "impcc"
      ]
    }
  ]
}

get/families/{author}/{slug}No key required

One family

The family with the full summary of every served model in it, in the shape GET /models uses, and every live endpoint across those models, so a family page needs exactly one call. Each endpoint row is the row GET /models/{author}/{slug}/endpoints publishes for that endpoint and names its own model_id; rows are ordered by model id, then provider slug, then endpoint id. benchmarks_note is the grading disclosure every benchmarks score on a row is read under. A family none of whose models is served answers 200 with "models": [] and "endpoints": [].

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the family id before the slash.

slugstringin pathRequired

The half of the family id after the slash.

Responses
StatusMeaning
200

The family, its served models newest first, and their live endpoints.

404

No such family.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/families/deepseek/deepseek-v4-flash-0731
Response
{
  "family": {
    "id": "deepseek/deepseek-v4-flash-0731",
    "name": "DeepSeek: DeepSeek V4 Flash 0731",
    "author": "deepseek",
    "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731"
  },
  "models": [
    {
      "id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "canonical_slug": "deepseek/deepseek-v4-flash-0731-abliterated",
      "hugging_face_id": "deepseek-ai/DeepSeek-V4-Flash-0731",
      "name": "DeepSeek: DeepSeek V4 Flash 0731 (abliterated)",
      "created": 1785611388,
      "expiration_date": null,
      "description": "A mixture-of-experts model tuned for speed.",
      "context_length": 131072,
      "architecture": {
        "modality": "text->text",
        "input_modalities": [
          "text"
        ],
        "output_modalities": [
          "text"
        ],
        "tokenizer": "DeepSeek",
        "instruct_type": null
      },
      "license": "mit",
      "parameter_count": 305723922366,
      "weights_dtype": "I8",
      "pricing": {
        "prompt": "0.0000001",
        "completion": "0.0000004",
        "request": "0",
        "input_cache_read": "0.000000037",
        "overrides": [
          {
            "min_prompt_tokens": 131071,
            "prompt": "0.0000002"
          }
        ]
      },
      "top_provider": {
        "context_length": 131072,
        "max_completion_tokens": 32768,
        "is_moderated": false
      },
      "per_request_limits": null,
      "supported_parameters": [
        "temperature",
        "top_p",
        "tools",
        "reasoning_effort"
      ],
      "reasoning": {
        "supported_efforts": [
          "high",
          "medium",
          "low",
          "none"
        ],
        "mandatory": false,
        "default_effort": "medium",
        "default_enabled": true,
        "supports_max_tokens": true
      },
      "default_parameters": {
        "temperature": 1,
        "top_p": 1
      },
      "hugging_face": {
        "id": "deepseek-ai/DeepSeek-V4-Flash-0731",
        "read_at": 1793817600,
        "availability": "public",
        "languages": [
          "en",
          "zh"
        ],
        "papers": [
          "2606.19348"
        ],
        "datasets": [
          "HuggingFaceM4/the_cauldron"
        ],
        "weights_revision": "0e9e39f249a16976918f6564b8830bc894c89659",
        "weights_updated_at": 1727283657,
        "downloads": 128473,
        "likes": 941,
        "evaluations": [
          {
            "task": "text-generation",
            "dataset": "HumanEval",
            "metrics": [
              {
                "name": "pass@1",
                "value": 71.3
              }
            ]
          }
        ]
      },
      "family": {
        "id": "deepseek/deepseek-v4-flash-0731",
        "name": "DeepSeek: DeepSeek V4 Flash 0731"
      },
      "author": "deepseek",
      "tags": [
        "abliterated",
        "moe"
      ],
      "endpoint_count": 1,
      "links": {
        "details": "/api/v1/models/deepseek/deepseek-v4-flash-0731-abliterated/endpoints"
      },
      "supported_voices": null,
      "supported_dimensions": null,
      "supported_languages": null
    }
  ],
  "endpoints": [
    {
      "name": "ImpCC | deepseek/deepseek-v4-flash-0731-abliterated",
      "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "model_name": "DeepSeek V4 Flash 0731",
      "provider_name": "ImpCC",
      "provider_slug": "impcc",
      "provider_id": "0b6f3c1e-8d2a-4f7b-9c1d-5e4a3b2c1d0e",
      "tag": "impcc/fp4",
      "context_length": 131072,
      "max_completion_tokens": 32768,
      "max_prompt_tokens": null,
      "quantization": "fp4",
      "supported_parameters": [
        "temperature",
        "tools",
        "reasoning_effort"
      ],
      "input_modalities": [
        "text"
      ],
      "declared_input_modalities": [
        "text"
      ],
      "capability_qualification": [],
      "reference_inputs": {},
      "render_parameters": {},
      "refuted_reasoning_efforts": [],
      "pricing": {
        "prompt": "0.0000001",
        "completion": "0.0000004",
        "input_cache_read": "0.000000037",
        "input_cache_write": "0.000000125",
        "input_cache_write_1h": "0.0000002",
        "overrides": [
          {
            "min_prompt_tokens": 131071,
            "prompt": "0.0000002"
          }
        ],
        "discount": 0.1
      },
      "status": 0,
      "health": "healthy",
      "uptime_last_5m": null,
      "uptime_last_5m_samples": 3,
      "uptime_last_30m": 100,
      "uptime_last_30m_samples": 14,
      "uptime_last_1d_samples": 90,
      "latency_last_30m": {
        "p50": 0.42,
        "p75": 0.55,
        "p90": 0.9,
        "p99": 1.4
      },
      "latency_last_30m_samples": 7,
      "throughput_last_30m": null,
      "throughput_last_30m_samples": 3,
      "perf_last_30m_by_workload": null,
      "supports_tool_choice": true,
      "supports_voice_cloning": false,
      "uptime_last_1d": 99.5,
      "uptime_last_7d": 99.2,
      "ttft_last_30m": {
        "p50": 0.42,
        "p75": 0.55,
        "p90": 0.9,
        "p99": 1.4
      },
      "ttft_last_1d": null,
      "response_last_30m": {
        "p50": 2.61,
        "p75": 3.1,
        "p90": 4,
        "p99": 6.2
      },
      "response_last_1d": null,
      "throughput_last_1d": {
        "p50": 85.1,
        "p75": 92,
        "p90": 98.4,
        "p99": 110.2
      },
      "throughput_last_1d_samples": 214,
      "render_timing": null,
      "render_timing_samples": 0,
      "render_timing_sizes": 0,
      "image_envelope": null,
      "video_envelope": null,
      "mesh_envelope": null,
      "decisions_envelope": null,
      "speech_envelope": null,
      "supports_implicit_caching": false,
      "compliance": {
        "zdr": true,
        "zdr_status": "approved",
        "hipaa": false
      },
      "data_policy": {
        "training": false,
        "retention_days": 0
      },
      "datacenters": [
        {
          "country_code": "CA"
        }
      ],
      "tool_call_success_1d": 98.2,
      "tool_call_success_1d_samples": 340,
      "runaway_rate_1d": 1.4,
      "runaway_rate_1d_samples": 620,
      "benchmarks": [],
      "capacity": {
        "current": 1,
        "total": 4,
        "updated_at": "2026-08-16T11:59:31.000Z"
      }
    }
  ],
  "benchmarks_note": "Scores are measured on this marketplace through the same routing customer traffic takes."
}

get/families/{author}/{slug}/seriesNo key required

A family's hourly health series

Per live endpoint across every served model in the family, the series GET /models/{author}/{slug}/series publishes for that endpoint: sparse ascending hourly buckets and recorded price changes, each row naming its model_id. No bucket is merged across endpoints or models. Rows are ordered by provider slug then endpoint id. Computed at most once a minute per gateway, and served for up to five minutes past that while it is recomputed; Last-Modified states when.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the family id before the slash.

slugstringin pathRequired

The half of the family id after the slash.

daysintegerin query—

Days of history, ending now.

1 to 7, defaults to 7
If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

One series per live endpoint in the family.

304

The body is the one If-None-Match names; no response body.

400

days is outside 1 to 7.

404

No such family.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/families/deepseek/deepseek-v4-flash-0731/series
Response
{
  "data": {
    "family_id": "deepseek/deepseek-v4-flash-0731",
    "window_days": 7,
    "endpoints": [
      {
        "endpoint_id": "5f0c…",
        "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
        "provider_slug": "impcc",
        "provider_id": "0b6f3c1e-8d2a-4f7b-9c1d-5e4a3b2c1d0e",
        "provider_name": "ImpCC",
        "quantization": "fp8",
        "hours": [
          {
            "hour": "2026-08-16T11:00:00.000Z",
            "ok": 118,
            "error": 2,
            "ttft_p50": 0.42,
            "ttft_p90": 0.9,
            "throughput_median": 63.1
          }
        ],
        "prices": [
          {
            "captured_at": "2026-08-10T09:00:00.000Z",
            "prompt": "0.0000001",
            "completion": "0.0000004",
            "cached_prompt": "0.000000037",
            "request": null,
            "image": null,
            "audio": null,
            "character": null
          }
        ]
      }
    ]
  }
}

get/families/{author}/{slug}/activity/seriesNo key required

A family's daily usage

The counts GET /models/{author}/{slug}/activity/series publishes, summed per UTC day over every active model in the family, a model with no live endpoint included. Every billed request counts, the marketplace's own paid probe traffic included. Counts only, no money. Sparse: a day without traffic has no entry. Computed at most once a minute per gateway, and served for up to five minutes past that while it is recomputed; Last-Modified states when.

Parameters
NameTypeRequiredDescription
authorstringin pathRequired

The half of the family id before the slash.

slugstringin pathRequired

The half of the family id after the slash.

daysintegerin query—

Days of history, ending today.

1 to 30, defaults to 30
If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

The daily counts across the family.

304

The body is the one If-None-Match names; no response body.

400

days is outside 1 to 30.

404

No such family.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/families/deepseek/deepseek-v4-flash-0731/activity/series
Response
{
  "data": {
    "family_id": "deepseek/deepseek-v4-flash-0731",
    "window_days": 30,
    "daily": [
      {
        "date": "2026-08-16",
        "requests": 12,
        "prompt_tokens": 90210,
        "completion_tokens": 4821,
        "images": 0,
        "megapixels": 0,
        "audio_seconds": 0
      }
    ]
  }
}

get/providersNo key required

List providers

Approved providers, with the policies and locations each of them declares. id is the provider's primary key and holds when its slug is changed, so a mirror keyed on id follows a renamed provider rather than seeing a new one.

Responses
StatusMeaning
200

The approved providers.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/providers
Response
{
  "data": [
    {
      "id": "0b6f3c1e-8d2a-4f7b-9c1d-5e4a3b2c1d0e",
      "name": "ImpCC",
      "slug": "impcc",
      "privacy_policy_url": "https://impcc.example/privacy",
      "terms_of_service_url": "https://impcc.example/terms",
      "status_page_url": null,
      "headquarters": "CA",
      "datacenters": [
        "CA"
      ],
      "website": "https://impcc.example",
      "model_count": 3
    }
  ]
}

get/providers/{slug}/seriesNo key required

A provider's hourly health series

One hourly ok/error series aggregated across all of the provider's live endpoints, with the status board's counting rules. Computed at most once a minute per gateway, and served for up to five minutes past that while it is recomputed; Last-Modified states when.

Parameters
NameTypeRequiredDescription
slugstringin pathRequired

The provider slug.

daysintegerin query—

Days of history, ending now.

1 to 7, defaults to 7
If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

The aggregated series.

304

The body is the one If-None-Match names; no response body.

400

days is outside 1 to 7.

404

No such approved provider.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/providers/impcc/series
Response
{
  "data": {
    "provider_slug": "impcc",
    "window_days": 7,
    "hours": [
      {
        "hour": "2026-08-16T11:00:00.000Z",
        "ok": 118,
        "error": 2
      }
    ]
  }
}

get/endpoints/zdrNo key required

The endpoints ZDR routing keeps

Every live endpoint the ZDR fold keeps, across the whole catalogue: a claim whose provider an operator approved. The same public endpoint shape GET /models/{author}/{slug}/endpoints publishes, ordered by model id then provider slug then endpoint id. A preview of what zdr: true routes to, or what GET /models?zdr=true matches. No key required.

Responses
StatusMeaning
200

The kept endpoints.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/endpoints/zdr
Response
{
  "data": [
    {
      "name": "ImpCC | deepseek/deepseek-v4-flash-0731-abliterated",
      "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "model_name": "DeepSeek V4 Flash 0731",
      "provider_name": "ImpCC",
      "provider_slug": "impcc",
      "provider_id": "0b6f3c1e-8d2a-4f7b-9c1d-5e4a3b2c1d0e",
      "tag": "impcc/fp4",
      "context_length": 131072,
      "max_completion_tokens": 32768,
      "max_prompt_tokens": null,
      "quantization": "fp4",
      "supported_parameters": [
        "temperature",
        "tools",
        "reasoning_effort"
      ],
      "input_modalities": [
        "text"
      ],
      "declared_input_modalities": [
        "text"
      ],
      "capability_qualification": [],
      "reference_inputs": {},
      "render_parameters": {},
      "refuted_reasoning_efforts": [],
      "pricing": {
        "prompt": "0.0000001",
        "completion": "0.0000004",
        "input_cache_read": "0.000000037",
        "input_cache_write": "0.000000125",
        "input_cache_write_1h": "0.0000002",
        "overrides": [
          {
            "min_prompt_tokens": 131071,
            "prompt": "0.0000002"
          }
        ],
        "discount": 0.1
      },
      "status": 0,
      "health": "healthy",
      "uptime_last_5m": null,
      "uptime_last_5m_samples": 3,
      "uptime_last_30m": 100,
      "uptime_last_30m_samples": 14,
      "uptime_last_1d_samples": 90,
      "latency_last_30m": {
        "p50": 0.42,
        "p75": 0.55,
        "p90": 0.9,
        "p99": 1.4
      },
      "latency_last_30m_samples": 7,
      "throughput_last_30m": null,
      "throughput_last_30m_samples": 3,
      "perf_last_30m_by_workload": null,
      "supports_tool_choice": true,
      "supports_voice_cloning": false,
      "uptime_last_1d": 99.5,
      "uptime_last_7d": 99.2,
      "ttft_last_30m": {
        "p50": 0.42,
        "p75": 0.55,
        "p90": 0.9,
        "p99": 1.4
      },
      "ttft_last_1d": null,
      "response_last_30m": {
        "p50": 2.61,
        "p75": 3.1,
        "p90": 4,
        "p99": 6.2
      },
      "response_last_1d": null,
      "throughput_last_1d": {
        "p50": 85.1,
        "p75": 92,
        "p90": 98.4,
        "p99": 110.2
      },
      "throughput_last_1d_samples": 214,
      "render_timing": null,
      "render_timing_samples": 0,
      "render_timing_sizes": 0,
      "image_envelope": null,
      "video_envelope": null,
      "mesh_envelope": null,
      "decisions_envelope": null,
      "speech_envelope": null,
      "supports_implicit_caching": false,
      "compliance": {
        "zdr": true,
        "zdr_status": "approved",
        "hipaa": false
      },
      "data_policy": {
        "training": false,
        "retention_days": 0
      },
      "datacenters": [
        {
          "country_code": "CA"
        }
      ],
      "tool_call_success_1d": 98.2,
      "tool_call_success_1d_samples": 340,
      "runaway_rate_1d": 1.4,
      "runaway_rate_1d_samples": 620,
      "benchmarks": [],
      "capacity": {
        "current": 1,
        "total": 4,
        "updated_at": "2026-08-16T11:59:31.000Z"
      }
    }
  ]
}

get/benchmarksNo key required

Current serving benchmark results

Named official benchmark suites and current serving variants. Results use current protocol-matched evidence within 30 days. Supported sample metrics publish provisional scores after five scored tasks; completed/expected records exact coverage. Only complete runs carry final official aggregates. Provisional averages require identical sample_fingerprint values. Costs are decimal USD strings and missing measurements are null. Computed at most once a minute per gateway, and served for up to an hour past that while it is recomputed; generated_at and Last-Modified state when. A reader waits at most six seconds for a computation and is otherwise answered 503 with Retry-After while it completes.

Parameters
NameTypeRequiredDescription
If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

Benchmark catalogue, run coverage, provenance and efficiency metrics in a data envelope.

304

The body is the one If-None-Match names; no response body.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

503

The figures are being computed and will be served shortly.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/benchmarks

get/benchmarks/variants/{endpointId}No key required

Benchmark task evidence for a serving variant

Current variant results and up to 1,000 task attempts per selected run. No customer requests, answer text, internal generation identifiers or credentials are included. Computed at most once a minute per gateway, and served for up to ten minutes past that while it is recomputed; Last-Modified states when. A reader waits at most six seconds for a computation and is otherwise answered 503 with Retry-After while it completes.

Parameters
NameTypeRequiredDescription
endpointIdstringin pathRequired

The currently served endpoint UUID.

If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

Variant and bounded task evidence in a data envelope.

304

The body is the one If-None-Match names; no response body.

404

Variant is not currently served.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

503

The figures are being computed and will be served shortly.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/benchmarks/variants/endpointId

get/stats/publicNo key required

Marketplace usage

Usage aggregates over the last 30 days for the public rankings and activity pages. Every billed request counts, the marketplace's own paid probe traffic included. Counts only, no money. Requests are the one measure every API type has, so models and authors are ranked on them; tokens is null where no request of the model, author or API type reported a token count, as for an image or video generation, and a null is never a zero. Unwrapped: no data envelope. Computed at most once a minute per gateway, and served for up to five minutes past that while it is recomputed; Last-Modified states when.

Parameters
NameTypeRequiredDescription
If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

The aggregates.

304

The body is the one If-None-Match names; no response body.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/stats/public
Response
{
  "totals": {
    "requests": 128410,
    "tokens": 984120333,
    "models_served": 42
  },
  "window_days": 30,
  "daily": [
    {
      "date": "2026-08-16",
      "requests": 4210,
      "prompt_tokens": 30112004,
      "completion_tokens": 1840221,
      "requests_by_api_type": {
        "chat": 3900,
        "images": 310
      },
      "tokens_by_api_type": {
        "chat": 31952225
      }
    }
  ],
  "api_types": [
    {
      "api_type": "chat",
      "requests": 118200,
      "tokens": 984120333
    },
    {
      "api_type": "images",
      "requests": 10210,
      "tokens": null
    }
  ],
  "models": [
    {
      "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "author": "deepseek",
      "name": "DeepSeek V4 Flash 0731",
      "api_type": "chat",
      "requests": 8102,
      "tokens": 61200311
    }
  ],
  "authors": [
    {
      "author": "deepseek",
      "requests": 8102,
      "tokens": 61200311,
      "share": 0.42
    }
  ]
}

get/site-discountNo key required

Active site promotion

The site promotion shown to customers. A provider endpoint discount counts toward the promotion; the customer receives the larger fraction. An absent or expired promotion returns discount: null. The response is not cached.

Responses
StatusMeaning
200

The active promotion or null.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/site-discount

get/promotionsNo key required

Active marketplace promotions

The site offer and approved providers with an active catalogue offer and a live model endpoint. An endpoint discount counts toward the larger active offer. The response is not cached.

Responses
StatusMeaning
200

Active site and provider promotions.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/promotions

get/statusNo key required

The status board

Every approved provider with its live endpoints' health, measured uptime, response time, the most recent error and success over a 7-day window, and a 24-hour hourly history. Response time rather than time to first token, because every endpoint has one and an endpoint that never streams has no first-token figure. uptime_1d_samples is the counted attempts behind uptime_1d, which is what separates a measured 100% from a lucky one. History buckets exist only for hours that had attempts. Unwrapped: no data envelope. Computed at most once every 30 seconds per gateway, and never served older than that: a read past it waits for the recomputation. Last-Modified states when.

Parameters
NameTypeRequiredDescription
If-None-Matchstringin header—

Validators from earlier responses; a current match returns 304 without a body.

Responses
StatusMeaning
200

The board, providers by slug and endpoints by model then endpoint id.

304

The body is the one If-None-Match names; no response body.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

ETag

Validator of the exact response body.

Last-Modified

When these figures were computed.

Request
curl https://api-staging.heimdallm.com/api/v1/status
Response
{
  "providers": [
    {
      "slug": "impcc",
      "name": "ImpCC",
      "endpoints": [
        {
          "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
          "endpoint_id": "5f0c…",
          "health": "healthy",
          "uptime_1d": 98.7,
          "uptime_1d_samples": 1240,
          "uptime_7d": 99.2,
          "response_p50": 2.61,
          "response_1d_p50": 2.74,
          "last_error": {
            "at": "2026-08-16T11:04:05.000Z",
            "status_code": 500,
            "error_type": "provider_error"
          },
          "last_success_at": "2026-08-16T11:59:31.000Z",
          "history": [
            {
              "hour": "2026-08-16T11:00:00.000Z",
              "ok": 118,
              "error": 2
            }
          ]
        }
      ]
    }
  ]
}

account

What the presented key has spent, and what its account has left.

get/keyBearer key

The presented key

What the key is, what it has spent and what its ceiling leaves. limit_remaining is measured over the window the ceiling resets in, so a monthly ceiling is compared against this month. A key with no ceiling reports null for all three ceiling fields rather than a zero.

Responses
StatusMeaning
200

The key.

401

The key is missing, unknown, revoked, expired or past its spend limit.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/key \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": {
    "label": "sk-hd-v1-3f9a…",
    "name": "production",
    "limit": 10,
    "limit_remaining": 4.5,
    "limit_reset": "monthly",
    "usage": 5.5,
    "usage_daily": 0.2,
    "usage_weekly": 1.1,
    "usage_monthly": 5.5,
    "is_free_tier": false,
    "expires_at": null
  }
}

get/auth/keyBearer key

The presented key (alias)

The same read as GET /key, served at the path a Bifrost OpenRouter provider validates a key against before it routes anything. Answers identically.

Responses
StatusMeaning
200

The key.

401

The key is missing, unknown, revoked, expired or past its spend limit.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/auth/key \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": {
    "label": "sk-hd-v1-3f9a…",
    "name": "production",
    "limit": 10,
    "limit_remaining": 4.5,
    "limit_reset": "monthly",
    "usage": 5.5,
    "usage_daily": 0.2,
    "usage_weekly": 1.1,
    "usage_monthly": 5.5,
    "is_free_tier": false,
    "expires_at": null
  }
}

get/creditsBearer key

The account's balance

Credited and debited totals for the account the key belongs to. The balance is the difference; both figures are exact.

Responses
StatusMeaning
200

The totals.

401

The key is missing, unknown, revoked, expired or past its spend limit.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/credits \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": {
    "total_credits": 100,
    "total_usage": 12.3
  }
}

get/generationBearer key

One generation

A recorded generation or a funded request awaiting a final record. record_state is recorded or unrecorded. An unrecorded request does not establish whether execution stopped: final tokens, timings and cost remain null, while reservation reports the recorded state and exact decimal amount. usage_observations contains up to 100 latest per-dispatch measurements, with usage_observations_truncated indicating omitted older attempts. Observations are not summed or declared billable; response_complete establishes receipt, not successful inference or final usage. Absent measurements remain null and explicit zero remains zero. Recorded image/video generations may carry media_billing, a versioned content-free receipt containing the frozen basis, native measurements, per-unit components and exact totalUsd; absent or unsupported receipts are null. Exact quantities use numerator and denominator integer strings. Historical pixel counts keep their unit. Recorded generations retain their recorded token, timing and cost fields; usage_reported carries the provenance of tokens_prompt and tokens_completion, and is true where the endpoint sent a usage document, false where it sent none and the two counts are therefore null, and null for a record written before the verdict existed. Scoped to the key's own account; an id on another account reads as absent.

Parameters
NameTypeRequiredDescription
idstringin queryRequired

The generation id, as returned in X-Generation-Id or the response id.

Responses
StatusMeaning
200

The generation record or retained request evidence.

400

id is missing or empty.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No generation or funded request with that id on the key's account.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/generation?id=gen-01J8Z0X2QZ \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": {
    "id": "gen-01J8Z0X2QZ",
    "record_state": "recorded",
    "model": "deepseek/deepseek-v4-flash-0731-abliterated",
    "provider_name": "ImpCC",
    "created_at": "2026-08-16T11:59:31.000Z",
    "streamed": true,
    "cancelled": false,
    "latency": 412,
    "generation_time": 2198,
    "finish_reason": "stop",
    "native_finish_reason": "stop",
    "tokens_prompt": 9,
    "tokens_completion": 3,
    "usage_reported": true,
    "native_tokens_prompt": 9,
    "native_tokens_completion": 3,
    "native_tokens_reasoning": null,
    "native_tokens_cached": null,
    "num_media_prompt": null,
    "total_cost": 0.0000021,
    "usage": 0.0000021,
    "cache_discount": null,
    "app_id": null,
    "upstream_id": "chatcmpl-abc"
  }
}

get/activityBearer key

The account's usage for one day

Requests, tokens and spend for one UTC day on the key's account, in the row shape OpenRouter's /activity publishes. Without date the day the account's daily spend window is currently in. group_by (default model) sets what a row is: model aggregates across every endpoint and key that served it, endpoint splits a model's rows by which endpoint served them, and key splits by which API key spent them and adds api_key_hash to every row. Grouping only ever splits a day's rows further; the sum of any field over a grouped day's rows equals the same model's row at the default grouping.

Parameters
NameTypeRequiredDescription
datestringin query—

The UTC day to report, YYYY-MM-DD.

matches ^\d{4}-\d{2}-\d{2}$
api_key_hashstringin query—

Restrict to one API key on the account, by its SHA-256 hash (the form /key and the request log publish, never the key itself).

matches ^[0-9a-f]{64}$
group_bystringin query—

How to split a day into rows: model (default), endpoint or key. See the operation description.

one of model, endpoint, key, defaults to model
user_idstringin query—

Rejected with a 400: the public API reports the whole account behind the key, not one organization member.

workspace_idstringin query—

Rejected with a 400: the public API reports the whole account behind the key, not one workspace within it.

Responses
StatusMeaning
200

One row per the requested grouping, ordered by model id.

400

date is not a UTC date in YYYY-MM-DD form, group_by is not model, endpoint or key, api_key_hash is not a 64-character lowercase hex hash, or user_id/workspace_id was sent.

401

The key is missing, unknown, revoked, expired or past its spend limit.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/activity \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": [
    {
      "date": "2026-08-16",
      "model": "deepseek/deepseek-v4-flash-0731-abliterated",
      "model_permaslug": "deepseek/deepseek-v4-flash-0731-abliterated",
      "endpoint_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "provider_name": "Example Compute",
      "requests": 12,
      "prompt_tokens": 90210,
      "completion_tokens": 4821,
      "reasoning_tokens": 512,
      "usage": "0.0213",
      "spend": "0.0213",
      "byok_usage_inference": "0"
    }
  ]
}

keys

The provisioning API: creating, listing, reading, editing and revoking keys with a management key. A management key manages keys only — it is refused on every route that spends or reports spend.

get/keysBearer key

List keys

Every key in the management key's own workspace, newest first. Served only to a management key.

Responses
StatusMeaning
200

The keys.

401

The key is missing, unknown, revoked, expired or past its spend limit.

403

A management key was sent to a route it cannot use: /keys is served only to a management key, and a management key is refused everywhere else because it never spends.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/keys \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": [
    {
      "hash": "3fa85f64571745...",
      "name": "customer instance",
      "label": "sk-hd-v1-3f9a…",
      "disabled": false,
      "limit": "10",
      "limit_reset": "monthly",
      "usage": "0",
      "created_at": "2026-08-16T11:59:31.000Z",
      "updated_at": "2026-08-16T11:59:31.000Z"
    }
  ]
}

post/keysBearer key

Create a key

A new key in the management key's own workspace. key carries the plaintext, returned once and never stored; data.hash is its SHA-256 hex, the identifier every other route in this section addresses it by. A key created here spends against the same account balance the management key's own workspace draws from.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
namestringRequired

A label for the key, up to 80 characters. Refused when it has the shape of a playground grant name.

limitstring | null—

A spend ceiling as a decimal USD string, or omitted/null for none. A decimal USD-per-million-token string such as "1.50", compared exactly against the endpoint's declared per-token price. Never a float.

limit_resetstring | null—

How the ceiling resets, or omitted/null for a lifetime ceiling.

one of daily, weekly, monthly, null
Responses
StatusMeaning
201

The key, with its plaintext.

400

The body did not parse, or name is the reserved shape of a playground grant.

401

The key is missing, unknown, revoked, expired or past its spend limit.

403

A management key was sent to a route it cannot use: /keys is served only to a management key, and a management key is refused everywhere else because it never spends.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/keys \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "name": "customer instance",  "limit": "10",  "limit_reset": "monthly"}'
Response
{
  "key": "sk-hd-v1-3f9a2c…",
  "data": {
    "hash": "3fa85f64571745...",
    "name": "customer instance",
    "label": "sk-hd-v1-3f9a…",
    "disabled": false,
    "limit": "10",
    "limit_reset": "monthly",
    "usage": "0",
    "created_at": "2026-08-16T11:59:31.000Z",
    "updated_at": "2026-08-16T11:59:31.000Z"
  }
}

get/keys/{hash}Bearer key

Read one key

One key, by the hash POST /keys or GET /keys reported for it.

Parameters
NameTypeRequiredDescription
hashstringin pathRequired

The key’s SHA-256 hex, as POST /keys or GET /keys reported it.

matches ^[0-9a-f]{64}$
Responses
StatusMeaning
200

The key.

401

The key is missing, unknown, revoked, expired or past its spend limit.

403

A management key was sent to a route it cannot use: /keys is served only to a management key, and a management key is refused everywhere else because it never spends.

404

No such key in the management key’s own workspace. Identical whether the hash is unknown or names a key elsewhere.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/keys/3fa85f64571745... \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": {
    "hash": "3fa85f64571745...",
    "name": "customer instance",
    "label": "sk-hd-v1-3f9a…",
    "disabled": false,
    "limit": "10",
    "limit_reset": "monthly",
    "usage": "0.42",
    "created_at": "2026-08-16T11:59:31.000Z",
    "updated_at": "2026-08-16T11:59:31.000Z"
  }
}

patch/keys/{hash}Bearer key

Edit a key

Every member is optional; at least one is required. disabled: true revokes the key exactly as DELETE does — the row stays and keeps its ledger attribution, it simply stops authenticating.

Parameters
NameTypeRequiredDescription
hashstringin pathRequired

The key’s SHA-256 hex, as POST /keys or GET /keys reported it.

matches ^[0-9a-f]{64}$
Request bodyapplication/json
Fields
NameTypeRequiredDescription
namestring—

Renames the key.

limitstring | null—

Replaces the spend ceiling; null removes it.

limit_resetstring | null—

Replaces the reset window; null makes the ceiling a lifetime one.

one of daily, weekly, monthly, null
disabledboolean—

True revokes the key exactly as DELETE does. False on an already-live key changes nothing.

Responses
StatusMeaning
200

The key as it now stands.

400

The body did not parse, or carried no member to change.

401

The key is missing, unknown, revoked, expired or past its spend limit.

403

A management key was sent to a route it cannot use: /keys is served only to a management key, and a management key is refused everywhere else because it never spends.

404

No such key in the management key’s own workspace. Identical whether the hash is unknown or names a key elsewhere.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl -X PATCH https://api-staging.heimdallm.com/api/v1/keys/3fa85f64571745... \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "limit": "25",  "limit_reset": "weekly"}'
Response
{
  "data": {
    "hash": "3fa85f64571745...",
    "name": "customer instance",
    "label": "sk-hd-v1-3f9a…",
    "disabled": false,
    "limit": "25",
    "limit_reset": "weekly",
    "usage": "0.42",
    "created_at": "2026-08-16T11:59:31.000Z",
    "updated_at": "2026-08-16T12:10:04.000Z"
  }
}

delete/keys/{hash}Bearer key

Revoke a key

Disables the key; the row stays and keeps its ledger attribution. Idempotent — revoking an already-revoked key answers the same way.

Parameters
NameTypeRequiredDescription
hashstringin pathRequired

The key’s SHA-256 hex, as POST /keys or GET /keys reported it.

matches ^[0-9a-f]{64}$
Responses
StatusMeaning
200

The key is revoked.

401

The key is missing, unknown, revoked, expired or past its spend limit.

403

A management key was sent to a route it cannot use: /keys is served only to a management key, and a management key is refused everywhere else because it never spends.

404

No such key in the management key’s own workspace. Identical whether the hash is unknown or names a key elsewhere.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl -X DELETE https://api-staging.heimdallm.com/api/v1/keys/3fa85f64571745... \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "data": {
    "success": true
  }
}

files

The per-account file store: upload once, address by id afterwards. A file belongs to the account its key draws from, and reads as absent to every other account. A file is a temporary handoff: it expires 48 hours after it is stored, and from then on every route answers 404 for it as for a deleted file. Its bytes are held sealed, under a key that lives outside the database and every copy of it, so a backup of the database holds nothing that opens a file more than 50 hours after it was stored. `/chat/completions`, `/responses` and `/messages` name a stored file by its id: the marketplace reads the bytes into the request and sends the provider a data URL, so the provider is never given the id and keeps nothing.

get/filesBearer key

List files

Every unexpired file on the key’s own account, newest first. next_cursor is the id to pass as after for the page behind this one, and is null on the last page.

Parameters
NameTypeRequiredDescription
limitintegerin query—

Files per page, 1 through 100. Defaults to 20.

1 to 100, defaults to 20
afterstringin query—

The id the previous page ended on. An id naming no file of this account is refused as unknown rather than answered as empty.

matches ^file_[0-9a-f]{32}$
Responses
StatusMeaning
200

One page of files.

400

limit is outside 1 through 100, or after names no file of this account.

401

The key is missing, unknown, revoked, expired or past its spend limit.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/files \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "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
    }
  ],
  "next_cursor": null
}

post/filesBearer key

Store a file

Stores one file on the account the key draws from, as multipart/form-data with the bytes in a file part. The file expires 48 hours after it is stored, and the response states the instant in expires_at. One file is capped at 32 MiB and an account at 512 MiB across every file it holds, counting only files that have not expired; the type must be one the store accepts (application/json, application/pdf, image/gif, image/jpeg, image/png, image/webp, text/csv, text/markdown, text/plain). A part sent as application/octet-stream is typed from its filename extension. The filename is kept as one path segment: separators, control characters and quotes are stripped from it.

Request bodymultipart/form-data

The file, in a part named file.

Responses
StatusMeaning
201

The file was stored.

400

The body was not multipart, carried no file part, carried an empty one, or named a type the store does not accept.

401

The key is missing, unknown, revoked, expired or past its spend limit.

409

Storing the file would put the account past its file quota. metadata carries quota_bytes, used_bytes and file_bytes, so a client can say how much to free.

413

The file is larger than the 32 MiB one file may hold.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

503

The key store that stored files are sealed under could not be reached. Retry shortly: this says nothing about the file, which is never reported absent because of it.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/files \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "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
  }
}

get/files/{id}Bearer key

Read one file’s metadata

What the store holds about one file, without its content. downloadable reports that the bytes are held and will be served at /files/{id}/content, and expires_at is the instant the file stops existing. A file past that instant answers 404, as a deleted one does.

Parameters
NameTypeRequiredDescription
idstringin pathRequired

The file id POST /files returned, of the form file_ followed by 32 hex characters.

matches ^file_[0-9a-f]{32}$
Responses
StatusMeaning
200

The file.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such file on the key’s own account. Identical whether the id is unknown, malformed, expired, deleted, or names a file another account stored. A file whose sealing key the key store has lost, which only a loss of its data causes, answers the same way for its content.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/files/id \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "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
  }
}

delete/files/{id}Bearer key

Delete a file

Removes the file and its content, and frees what it held against the account quota. Not idempotent: a second delete answers 404, because a file that is gone and a file that was never stored are the same answer.

Parameters
NameTypeRequiredDescription
idstringin pathRequired

The file id POST /files returned, of the form file_ followed by 32 hex characters.

matches ^file_[0-9a-f]{32}$
Responses
StatusMeaning
200

The file is gone.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such file on the key’s own account. Identical whether the id is unknown, malformed, expired, deleted, or names a file another account stored. A file whose sealing key the key store has lost, which only a loss of its data causes, answers the same way for its content.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

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

get/files/{id}/contentBearer key

Download a file

The stored bytes, served whole under the type the file was stored as, with the filename in Content-Disposition. Ranges are not offered. The bytes are held sealed under a key that lives outside the database, so this reads them back only while that key exists, which is for longer than the file lives.

Parameters
NameTypeRequiredDescription
idstringin pathRequired

The file id POST /files returned, of the form file_ followed by 32 hex characters.

matches ^file_[0-9a-f]{32}$
Responses
StatusMeaning
200

The file content.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such file on the key’s own account. Identical whether the id is unknown, malformed, expired, deleted, or names a file another account stored. A file whose sealing key the key store has lost, which only a loss of its data causes, answers the same way for its content.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

503

The key store that stored files are sealed under could not be reached. Retry shortly: this says nothing about the file, which is never reported absent because of it.

Content-Disposition

attachment, with the filename the file was stored under.

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

batches

Requests submitted together and run in the background. Every request of a batch is an ordinary request to its endpoint, routed, held, settled and billed exactly as the same body posted to that route would be; a batch is a way to submit them and carries no discount. The outcome of each is written to a file in the account’s file store when the batch ends.

get/batchesBearer key

List batches

Batches on the key’s own account, newest first. status may be repeated to include several. created_after and created_before take unix seconds, a date or an ISO 8601 instant, and exclude the instant itself. To read the next page, pass the previous page’s last_id as after; there is no offset. Every item carries results: null, and GET /batches/{id} has the results.

Parameters
NameTypeRequiredDescription
limitintegerin query—

Batches per page, 1 through 100. Defaults to 20.

1 to 100, defaults to 20
afterstringin query—

The last_id of the previous page. An id naming no batch of this account is refused as unknown rather than answered as empty.

matches ^batch_[0-9a-f]{32}$
statusarray<string>in query—

Only batches in this status. Repeat the parameter to include more than one.

one of validating, in_progress, cancelling, completed, failed, expired, cancelled
created_afterstringin query—

Only batches created strictly after this instant.

created_beforestringin query—

Only batches created strictly before this instant.

Responses
StatusMeaning
200

One page of batches, newest first.

400

limit is outside 1 through 100, status names no status, a time bound names no instant, or after names no batch of this account.

401

The key is missing, unknown, revoked, expired or past its spend limit.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/batches \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "object": "list",
  "data": [
    {
      "id": "batch_5d1f0c9e2a7b4e36b8a4c1d27e90f3a5",
      "object": "batch",
      "endpoint": "/v1/chat/completions",
      "model": "acme/alpha-v1",
      "completion_window": "24h",
      "status": "validating",
      "created_at": 1786881571,
      "expires_at": 1786967971,
      "finalized_at": null,
      "request_counts": {
        "total": 2,
        "completed": 0,
        "failed": 0
      },
      "results_file_id": null,
      "results": null,
      "error": null
    }
  ],
  "first_id": "batch_5d1f0c9e2a7b4e36b8a4c1d27e90f3a5",
  "last_id": "batch_5d1f0c9e2a7b4e36b8a4c1d27e90f3a5",
  "has_more": false
}

post/batchesBearer key

Submit a batch

Submits requests to run in the background against one endpoint: /v1/chat/completions, /v1/responses or /v1/messages. Answers 202 with status: "validating" once the batch is stored; nothing has run or been charged yet. requests holds up to 1000 items of { custom_id, body }, each custom_id unique within the batch and each body the request its endpoint takes, with stream left out because every request is answered in full. model and provider (only, allow_fallbacks), when stated, apply to every request that does not state its own; a body that names a different model fails on its own. Each body is parsed against the endpoint's schema when the batch is accepted, and one that does not parse fails alone, in the results, with the error the live route would have answered, while the rest of the batch runs. A batch whose every request fails that way ends failed. Every request is routed, held, settled and billed exactly as the same body posted to the endpoint would be, under the key that submitted the batch and its spend limit as it stands when the request is sent, and carries a generation of its own; a batch earns no discount. A request the account cannot fund, or no endpoint serves, fails alone with that answer. Requests run oldest batch first, at most 8 of an account's at a time by default. An account may have 10 batches waiting or running at once. A batch still running when its completion window closes ends expired. The outcome of each request is written as one line of a file in the account's file store when the batch ends, and the requests and replies the batch held are cleared in the same step. While the batch runs they are stored sealed, under a key that lives outside the database and is destroyed no more than 50 hours after the value was written. A request whose key is gone when its turn comes is not sent and is not charged; a charged request whose reply is gone when the batch ends fails with the charge named in error.request_id, and is not run again.

Request bodyapplication/json

Requests to run together against one endpoint. The members are exactly these; anything else is refused.

Fields
NameTypeRequiredDescription
endpointstringRequired

The request shape every body is written in: the route of the same name, under /v1.

one of /v1/chat/completions, /v1/responses, /v1/messages
modelstring—

A model for every request. A request whose body names no model takes it; one that names a different model fails on its own.

providerobject—

Provider preferences for every request whose body states none: the providers to use, and whether to fall back past them.

completion_windowstring—

How long the batch has to end, from its submission. A request not sent by then is not sent, and the batch ends expired.

one of 24h, defaults to 24h
requestsarray<object>Required

The requests, each a custom_id unique within the batch and a body.

Responses
StatusMeaning
202

The batch was stored. status is validating until the runner takes it, and nothing has run yet; request_counts.failed already counts any request whose body did not parse.

400

The envelope did not parse: an endpoint the API does not batch, no requests or more than the batch holds, a custom_id missing or repeated, a body that is not an object, or a member the submission does not take. A body that does not parse against its endpoint is not this error; it fails alone, in the results.

401

The key is missing, unknown, revoked, expired or past its spend limit.

413

The request body is larger than this route accepts. The inline assets a request carries are bounded by their own decoded-byte budget, which is read only once a body has arrived; a body over the route’s size limit is refused here instead.

429

The account already has 10 batches waiting or running, or the key is over its request rate. metadata carries limit and active for the first.

500

The marketplace failed to serve the request.

503

The key store that requests are stored sealed under could not be reached. Nothing was stored: repeat the submission shortly.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/batches \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "endpoint": "/v1/chat/completions",  "model": "acme/alpha-v1",  "completion_window": "24h",  "requests": [    {      "custom_id": "req-0001",      "body": {        "messages": [          {            "role": "user",            "content": "Summarize the first report."          }        ]      }    },    {      "custom_id": "req-0002",      "body": {        "messages": [          {            "role": "user",            "content": "Summarize the second report."          }        ]      }    }  ]}'
Response
{
  "id": "batch_5d1f0c9e2a7b4e36b8a4c1d27e90f3a5",
  "object": "batch",
  "endpoint": "/v1/chat/completions",
  "model": "acme/alpha-v1",
  "completion_window": "24h",
  "status": "validating",
  "created_at": 1786881571,
  "expires_at": 1786967971,
  "finalized_at": null,
  "request_counts": {
    "total": 2,
    "completed": 0,
    "failed": 0
  },
  "results_file_id": null,
  "results": null,
  "error": null
}

get/batches/{id}Bearer key

Retrieve a batch

A batch with its status and request counts. completed, failed, expired and cancelled are terminal. A batch that has ended carries results_file_id, the file its results were written to, and results, the same lines inline in submission order, for as long as that file is held, which is 48 hours from the batch ending. After that both are null and the batch still reports how it ended and its counts. request_counts.completed and .failed are the requests that ended in each way; a request stopped or expired before it was sent is in neither, so total less the two is what the batch did not run. A failed batch states the reason in error.message. Each result has exactly one of response and error. response.body is what the endpoint answered, response.request_id is the id the request was billed under and X-Generation-Id carries on a live request, and error names the type and message of the answer the live route would have given.

Parameters
NameTypeRequiredDescription
idstringin pathRequired

The batch id POST /batches returned, of the form batch_ followed by 32 hex characters.

matches ^batch_[0-9a-f]{32}$
Responses
StatusMeaning
200

The batch as it stands.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such batch on the key’s own account. Identical whether the id is unknown, malformed, or names a batch another account submitted.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/batches/id \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "id": "batch_5d1f0c9e2a7b4e36b8a4c1d27e90f3a5",
  "object": "batch",
  "endpoint": "/v1/chat/completions",
  "model": "acme/alpha-v1",
  "completion_window": "24h",
  "status": "completed",
  "created_at": 1786881571,
  "expires_at": 1786967971,
  "finalized_at": 1786881702,
  "request_counts": {
    "total": 2,
    "completed": 1,
    "failed": 1
  },
  "results_file_id": "file_2f1c4a7e9b0d46538a1c7e5f3b204d61",
  "results": [
    {
      "id": "breq_7e0c1a94d3b84f2a9c56e81d0b3f2a47",
      "custom_id": "req-0001",
      "response": {
        "status_code": 200,
        "request_id": "gen-1786881609-aBcDeFgHiJkLmNoPqRsT",
        "body": {
          "id": "gen-1786881609-aBcDeFgHiJkLmNoPqRsT",
          "object": "chat.completion"
        }
      },
      "error": null
    },
    {
      "id": "breq_a3c4e5f6071829304a5b6c7d8e9f0a1b",
      "custom_id": "req-0002",
      "response": null,
      "error": {
        "type": "invalid_request",
        "message": "Invalid request: messages: Too small: expected array to have >=1 items",
        "param": null,
        "code": 400,
        "request_id": null
      }
    }
  ],
  "error": null
}

post/batches/{id}/cancelBearer key

Cancel a batch

Stops a batch. Dispatch stops at once and the requests already in flight are cut; status is cancelling until what ran has settled, and the batch then becomes cancelled. A request that completed keeps its reply and its charge. A request that was cut, or had not been sent, is listed in the results as stopped and is not charged, except where it was charged before it was cut, in which case its error names the charge in request_id. Cancelling a batch that is already cancelling or cancelled answers its document unchanged. A batch that ended another way cannot be cancelled and answers 409.

Parameters
NameTypeRequiredDescription
idstringin pathRequired

The batch id POST /batches returned, of the form batch_ followed by 32 hex characters.

matches ^batch_[0-9a-f]{32}$
Responses
StatusMeaning
200

The batch, cancelling or already cancelled.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

No such batch on the key’s own account. Identical whether the id is unknown, malformed, or names a batch another account submitted.

409

The batch already ended as completed, failed or expired.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/batches/id/cancel \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "id": "batch_5d1f0c9e2a7b4e36b8a4c1d27e90f3a5",
  "object": "batch",
  "endpoint": "/v1/chat/completions",
  "model": "acme/alpha-v1",
  "completion_window": "24h",
  "status": "cancelling",
  "created_at": 1786881571,
  "expires_at": 1786967971,
  "finalized_at": null,
  "request_counts": {
    "total": 2,
    "completed": 0,
    "failed": 0
  },
  "results_file_id": null,
  "results": null,
  "error": null
}

deposits

Funding an account. The card rail describes itself here; the x402 rail settles here.

get/deposits/x402No key required

The x402 rail terms

What the signed-authorization deposit rail accepts, or { "enabled": false } and nothing else when it is not configured: an address or a network published by a rail that cannot take a payment describes an offer no client could tell from a payable one. No key required, so an agent can read the terms before holding one.

Responses
StatusMeaning
200

The terms, or the flag on its own.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/deposits/x402
Response
{
  "enabled": true,
  "x402_version": 2,
  "scheme": "exact",
  "pay_to": "0x0000000000000000000000000000000000000000",
  "min_amount": "1",
  "max_amount": "1000",
  "max_timeout_seconds": 120,
  "networks": [
    {
      "network": "eip155:8453",
      "chain_id": 8453,
      "chain_name": "Base",
      "asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
      "asset_symbol": "USDC",
      "asset_decimals": 6,
      "confirmations": 60,
      "confirmation_seconds": 120
    }
  ]
}

post/deposits/x402Key optional

Settle an x402 deposit

Without a PAYMENT-SIGNATURE header the answer is a 402 carrying the protocol's own PaymentRequired object, which is not the house error envelope every other 402 on this API is. Resubmitting with the base64 PaymentPayload in that header verifies and settles it. The credit posts at the chain's confirmation depth, not with the response. Which account a settled payment credits is decided by the payer's wallet binding where one exists, and by the presenting key otherwise; a key naming a different account than the binding is a 409 refused before anything settles. An authorization is identified by its chain, asset, payer and EIP-3009 nonce, so the same nonce can never settle twice and replaying one answers what was recorded for it.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
amountstringRequired

USD as an exact decimal string, such as "25" or "25.00". A number is refused: a float amount stops meaning what it says.

networkstring—

CAIP-2 network id, such as eip155:8453. Optional where the rail quotes one chain, which leaves nothing to choose between.

Responses
StatusMeaning
200

Settled, or recorded as settling where the outcome never came back. PAYMENT-RESPONSE carries the same SettlementResponse base64-encoded.

400

The amount is not a decimal USD figure, falls outside the published bounds, or carries more decimal places than the asset does. The bounds are re-read on every submission rather than carried on the offer.

402

The protocol's PaymentRequired object, also carried base64-encoded in PAYMENT-REQUIRED. Accepted assets with a pinned EIP-712 domain include extra.name and extra.version; Base native USDC uses USD Coin / 2.

409

The rail is not configured, the key names an account the payer's wallet binding contradicts, or the authorization credits nobody.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/deposits/x402 \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "amount": "25.00",  "network": "eip155:8453"}'
Response
{
  "data": {
    "id": "dep_01J8Z0X2QZ",
    "status": "settled",
    "network": "eip155:8453",
    "transaction": "0xabc…",
    "payer": "0xdef…",
    "amount": "25",
    "confirmations": 60,
    "confirmation_seconds": 120
  }
}

get/deposits/stripeNo key required

The card rail terms

The bounds a card deposit may fall between and the publishable key a browser is sent to Checkout with, or { "enabled": false } and nothing else. Nothing here takes money: the Checkout Session is created on the browser session plane, where a signed-in account names who the credit lands on.

Responses
StatusMeaning
200

The terms, or the flag on its own.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/deposits/stripe
Response
{
  "enabled": true,
  "publishable_key": "pk_live_…",
  "min_amount": "5",
  "max_amount": "2000",
  "currency": "usd"
}

post/deposits/stripe/webhookNo key required

Card payment events

Where Stripe delivers what became of a Checkout Session. Listed because it is served on this plane, not because a customer calls it. The signature is the authentication, so no key and no cookie apply, and the body is read as the bytes that arrived rather than as a parsed object, because a re-serialized parse verifies only by luck. A 2xx tells Stripe to stop retrying, so it is answered only once the event is durably resolved.

Request bodyapplication/json

The Stripe event, verbatim, at most 64 KiB, signed in the Stripe-Signature header.

Responses
StatusMeaning
200

The event was resolved and will not be delivered again.

400

The signature does not verify against a secret the card rail holds.

404

The card rail is not configured here.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

503

The card rail holds no webhook secret to verify a delivery against, so the event must be delivered again.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/deposits/stripe/webhook
Response
{
  "received": true
}

auth

Obtaining a key. An application sends a person to the marketplace to approve one and trades the resulting code for it, so the key it ends up holding is one the person can see and revoke.

post/auth/keysNo key required

Trade an authorization code for a key

The second half of the PKCE flow. An application sends a person to /auth on the site with a callback_url and the S256 code_challenge of a verifier it keeps; approving there returns the browser to the callback with a one-time code, and this route trades that code and the verifier for a key. The code lives ten minutes and is consumed as it is read, so a retry is refused exactly as a replay is. The key belongs to the approving account, is named after the callback origin, and is listed and revocable beside every other key on their account page. No credential opens this route: the code is the credential, and it is worth nothing without the verifier.

Request bodyapplication/json
Fields
NameTypeRequiredDescription
codestringRequired

The one-time code the callback URL was returned to the application with.

code_verifierstringRequired

The secret the application generated before sending the browser to /auth and hashed into code_challenge. 43 to 128 characters from A-Z a-z 0-9 - . _ ~, per RFC 7636.

code_challenge_methodstring—

S256, the only method served. A plain challenge travels in the address bar as the very secret this exchange asks for, which is what PKCE exists to avoid.

one of S256
callback_urlstring—

The callback the code was issued for. Optional; when sent it must match, which binds a code to the address the application published rather than only to the verifier.

Responses
StatusMeaning
200

The key, in plaintext. It is shown here and nowhere else.

400

The body did not parse, or the code is unknown, expired, already exchanged, issued for another callback, or does not match the verifier. The four are one message: telling them apart would say which codes exist.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/auth/keys \  -H "Content-Type: application/json" \  -d '{  "code": "9f1c0a2e5d7b4c8f",  "code_verifier": "nR3kQ7pY1sW9zL5xV2bH8mJ4tC6dF0gA3eU7iO1yP5q",  "code_challenge_method": "S256"}'
Response
{
  "key": "sk-hd-v1-3f9a…",
  "user_id": "usr_01J8Z0X2QZ"
}

service

The plane itself.

get/No key required

Name the API

A liveness read that names the plane. Nothing about the caller is read.

Responses
StatusMeaning
200

The plane answered.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/
Response
{
  "name": "Heimdallm API",
  "status": "ok"
}

provider

The provider dashboard's own reads, published to the same key a customer authenticates with: what the presented key's provider is serving and how it is measured, its earnings and statements, and a request for a fresh pull of its models document. Served only to a key whose account belongs to a provider.

get/providers/statusBearer key

The presented key's provider: endpoints and last pull

The provider the presented key's account belongs to: every live, pending-health, provider-not-ready or disabled endpoint it serves, with the same health, measured figures and pricing GET /models/{author}/{slug}/endpoints publishes about them to a customer choosing one, beside the outcome of the most recent pull of any of the provider's source documents. Each endpoint also carries its probe schedule as last_probe, and what its newest failed probe was answered with as last_failure — including the status your own server returned and the path it was asked for, which is the one place an origin routing a rail nowhere can be told from a marketplace fault. Both are null where there is nothing to report, never a zero. last_pull is null before the first pull. Withdrawn endpoints are not listed and are not counted; the provider dashboard's own include=withdrawn view has no equivalent here.

Responses
StatusMeaning
200

The provider's endpoints and its last pull.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

The presented key’s account does not belong to a provider.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/providers/status \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "models": [
    {
      "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "model_name": "Acme: Base 1",
      "endpoint_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "status": "live",
      "health_tier": "healthy",
      "quantization": "fp16",
      "context_length": 131072,
      "max_completion_tokens": 8192,
      "pricing": {
        "prompt": "0.000002",
        "completion": "0.000004"
      },
      "measured_at": "2026-08-16T11:59:31.000Z",
      "uptime_samples": 1240,
      "ttft_samples": 84,
      "response_samples": 84,
      "uptime_last_5m": 100,
      "uptime_last_5m_samples": 12,
      "uptime_last_30m": 100,
      "uptime_last_30m_samples": 60,
      "uptime_last_1d": 98.7,
      "uptime_last_1d_samples": 1240,
      "uptime_last_7d": 99.2,
      "latency_last_30m": null,
      "latency_last_30m_samples": 3,
      "throughput_last_30m": null,
      "throughput_last_30m_samples": 3,
      "throughput_last_1d": null,
      "throughput_last_1d_samples": 3,
      "ttft_last_30m": null,
      "ttft_last_1d": null,
      "response_last_30m": {
        "p50": 2.61,
        "p75": 2.9,
        "p90": 3.4,
        "p99": 4.1
      },
      "response_last_1d": {
        "p50": 2.74,
        "p75": 3.05,
        "p90": 3.5,
        "p99": 4.3
      },
      "perf_last_30m_by_workload": null,
      "render_timing": null,
      "render_timing_samples": 0,
      "render_timing_sizes": 0,
      "tool_call_success_1d": 98.2,
      "tool_call_success_1d_samples": 340,
      "runaway_rate_1d": 1.4,
      "runaway_rate_1d_samples": 620,
      "zdr_status": null,
      "zdr_note": null,
      "last_probe": {
        "at": "2026-08-16T11:59:31.000Z",
        "outcome": "success",
        "error": null,
        "requested_at": null,
        "next_at": "2026-08-16T12:29:31.000Z"
      },
      "last_failure": null,
      "first_seen_at": "2026-06-01T00:00:00.000Z",
      "last_seen_at": "2026-08-16T11:59:31.000Z"
    },
    {
      "model_id": "acme/rerank-1",
      "model_name": "Acme: Rerank 1",
      "endpoint_id": "7c2d1b90-4e6a-4f3b-9c5d-8a1e2f4b6c0d",
      "status": "pending_health",
      "health_tier": "unknown",
      "quantization": null,
      "context_length": 8192,
      "max_completion_tokens": null,
      "pricing": {
        "request": "0.000002"
      },
      "measured_at": null,
      "uptime_samples": null,
      "ttft_samples": null,
      "response_samples": null,
      "uptime_last_5m": null,
      "uptime_last_5m_samples": null,
      "uptime_last_30m": null,
      "uptime_last_30m_samples": null,
      "uptime_last_1d": null,
      "uptime_last_1d_samples": null,
      "uptime_last_7d": null,
      "latency_last_30m": null,
      "latency_last_30m_samples": null,
      "throughput_last_30m": null,
      "throughput_last_30m_samples": null,
      "throughput_last_1d": null,
      "throughput_last_1d_samples": null,
      "ttft_last_30m": null,
      "ttft_last_1d": null,
      "response_last_30m": null,
      "response_last_1d": null,
      "perf_last_30m_by_workload": null,
      "render_timing": null,
      "render_timing_samples": null,
      "render_timing_sizes": null,
      "tool_call_success_1d": null,
      "tool_call_success_1d_samples": null,
      "runaway_rate_1d": null,
      "runaway_rate_1d_samples": null,
      "zdr_status": null,
      "zdr_note": null,
      "last_probe": {
        "at": "2026-08-16T11:57:02.000Z",
        "outcome": "error",
        "error": "the endpoint answered 502 provider_unavailable",
        "requested_at": "2026-08-16T11:56:40.000Z",
        "next_at": "2026-08-16T12:57:02.000Z"
      },
      "last_failure": {
        "at": "2026-08-16T11:57:02.000Z",
        "status": 502,
        "error_type": "provider_unavailable",
        "upstream_status": 404,
        "upstream_path": "/v1/rerank",
        "upstream_message": "not found"
      },
      "first_seen_at": "2026-08-10T00:00:00.000Z",
      "last_seen_at": "2026-08-16T11:57:02.000Z"
    }
  ],
  "withdrawn_count": 0,
  "last_pull": {
    "id": "9c1f6a2e-1b3d-4c5f-8a7e-2d6b0c4f8a1e",
    "source_id": "5f0c7e2a-3b1d-4a6f-9c8e-1d2b3a4c5e6f",
    "trigger": "manual",
    "outcome": "ok",
    "http_status": 200,
    "started_at": "2026-08-16T11:58:00.000Z",
    "finished_at": "2026-08-16T11:58:04.000Z",
    "models_seen": 1,
    "endpoints_upserted": 1,
    "endpoints_withdrawn": 0,
    "errors": [],
    "warnings": []
  }
}

post/providers/pull-nowBearer key

Pull the presented key's provider's models document now

Re-reads one of the provider's source documents immediately rather than waiting for its schedule, and returns the resulting pull run. source_id names which source; it is optional only where the provider holds exactly one active (enabled, not admin-disabled) source, and required where it holds more than one. Refused, at the same interval the schedule itself keeps to, when the named source (or the provider's whole set of sources when none is named) was pulled too recently — Retry-After names when it may be asked again. The provider must be approved.

Request bodyapplication/json
Responses
StatusMeaning
200

The pull that was just run.

400

source_id is not a UUID, names no source of this provider, or was left out while the provider holds more than one active source.

401

The key is missing, unknown, revoked, expired or past its spend limit.

403

The provider is not approved.

404

The presented key’s account does not belong to a provider.

409

The named source is disabled, or the provider holds no active source to pull.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/providers/pull-now \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{}'
Response
{
  "run": {
    "id": "9c1f6a2e-1b3d-4c5f-8a7e-2d6b0c4f8a1e",
    "source_id": "5f0c7e2a-3b1d-4a6f-9c8e-1d2b3a4c5e6f",
    "trigger": "manual",
    "outcome": "ok",
    "http_status": 200,
    "started_at": "2026-08-16T11:58:00.000Z",
    "finished_at": "2026-08-16T11:58:04.000Z",
    "models_seen": 1,
    "endpoints_upserted": 1,
    "endpoints_withdrawn": 0,
    "errors": [],
    "warnings": []
  }
}

post/providers/probe-nowBearer key

Probe one of the presented key’s provider’s endpoints now

Makes one endpoint due for a health probe immediately rather than waiting out the failure backoff, which holds a repeatedly failing endpoint for as long as its streak says. endpoint_id names the endpoint and must be one of this provider's; a withdrawn endpoint, and one belonging to somebody else, are both answered as though they did not exist. The answer is the schedule rather than a verdict: the probe runs on the marketplace's next tick, and the request has been served once last_probe on GET /providers/status reports an at newer than its requested_at. Refused when the endpoint was probed, or asked for, too recently — Retry-After names when it may be asked again. The provider must be approved.

Request bodyapplication/json
Responses
StatusMeaning
200

The endpoint’s schedule, with the request recorded on it.

400

endpoint_id is missing or is not a UUID.

401

The key is missing, unknown, revoked, expired or past its spend limit.

403

The provider is not approved.

404

The presented key’s account does not belong to a provider, or names no endpoint of it.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl -X POST https://api-staging.heimdallm.com/api/v1/providers/probe-now \  -H "Authorization: Bearer $HEIMDALL_API_KEY" \  -H "Content-Type: application/json" \  -d '{  "endpoint_id": "7c2d1b90-4e6a-4f3b-9c5d-8a1e2f4b6c0d"}'
Response
{
  "schedule": {
    "endpoint_id": "7c2d1b90-4e6a-4f3b-9c5d-8a1e2f4b6c0d",
    "requested_at": "2026-08-16T12:04:00.000Z",
    "next_probe_at": "2026-08-16T12:04:00.000Z",
    "last_probe_at": "2026-08-16T11:57:02.000Z"
  }
}

get/providers/earningsBearer key

The presented key's provider's earnings

The provider's earnings for one month: totals, a breakdown by model, and a breakdown by the statement that claims each part (a part not yet claimed by any statement reads statement: null). Every amount is an exact decimal USD string. Without month, the current month.

Parameters
NameTypeRequiredDescription
monthstringin query—

The UTC month to report, YYYY-MM. Defaults to the current month.

matches ^\d{4}-(0[1-9]|1[0-2])$
Responses
StatusMeaning
200

The month's earnings.

400

month is not formatted YYYY-MM.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

The presented key’s account does not belong to a provider.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/providers/earnings \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "month": "2026-08",
  "totals": {
    "gross": "182.400000",
    "platform_cut": "18.240000",
    "net": "164.160000",
    "generation_count": 9130
  },
  "by_model": [
    {
      "model_id": "deepseek/deepseek-v4-flash-0731-abliterated",
      "gross": "182.400000",
      "platform_cut": "18.240000",
      "net": "164.160000",
      "generation_count": 9130
    }
  ],
  "by_statement": [
    {
      "statement": {
        "id": "2c9e4f7a-8b1d-4e6a-9f3c-7d2b5a8e1c4f",
        "period_start": "2026-08-01",
        "period_end": "2026-09-01",
        "status": "open",
        "payout_reference": null,
        "paid_at": null
      },
      "gross": "182.400000",
      "platform_cut": "18.240000",
      "net": "164.160000",
      "generation_count": 9130
    }
  ]
}

get/providers/statementsBearer key

The presented key's provider's statement history

Every statement issued to the provider, newest period first. earliest_earned_month is the earliest month of an earning the statement claims, which reads earlier than period_start when the statement picked up an earning that settled after its own month was already paid.

Responses
StatusMeaning
200

The statement history.

401

The key is missing, unknown, revoked, expired or past its spend limit.

404

The presented key’s account does not belong to a provider.

429

Too many requests for the key, or for the address when no key was sent. Retry-After says when to try again.

500

The marketplace failed to serve the request.

Request
curl https://api-staging.heimdallm.com/api/v1/providers/statements \  -H "Authorization: Bearer $HEIMDALL_API_KEY"
Response
{
  "statements": [
    {
      "id": "2c9e4f7a-8b1d-4e6a-9f3c-7d2b5a8e1c4f",
      "period_start": "2026-07-01",
      "period_end": "2026-08-01",
      "gross": "150.000000",
      "platform_cut": "15.000000",
      "net": "135.000000",
      "generation_count": 8010,
      "status": "paid",
      "payout_reference": "0xabc123…",
      "paid_at": "2026-08-05T00:00:00.000Z",
      "created_at": "2026-08-01T00:05:00.000Z",
      "earliest_earned_month": "2026-07"
    }
  ]
}
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