POST /v3/chat/completions, which speaks OpenAI’s chat completions format. Point the stock OpenAI SDK at https://api.hedra.com/v3, pass your Hedra API key, and pay for each request from the same prepaid API wallet as your media jobs. POST /v3/responses serves the same models in OpenAI’s Responses format (Responses API), and POST /v3/anthropic/v1/messages serves them in Anthropic’s Messages format, for the Anthropic SDK (Messages API). To run Claude Code, Codex CLI, OpenCode or Pi on these models, see Coding agents.
Before you start
- A key with the
chat:writescope. Create one in the developer console. A key created without a list of scopes has every scope. - A funded API wallet. Add funds in the developer console.
Authenticate
Pass your Hedra API key asapi_key, in either its <key_id>:<secret> form or as a legacy sk_hedra_… key. The SDK sends it as Authorization: Bearer <api_key>.
Choose a model
A chat model’s id is its fullorg/model id, matched without regard to case:
GET /v3/models lists them with each model’s context_length, max_output_tokens and per-token prices. GET /v3/models/{model} also returns the model’s input_schema, the JSON Schema of the requests it accepts: for example, moonshotai/kimi-k3 accepts top_p only as 0.95 and temperature only from 0 to 1. A bare id such as kimi-k3 returns 404, and the message names the full id.
The examples below use zai-org/glm-5.3.
Send a request
max_tokens nor max_completion_tokens, its output is limited to 4,096 tokens, or to the model’s max_output_tokens if that is lower. A max_tokens above max_output_tokens returns 400.
A non-streaming request must finish within 120 seconds. After that the API answers 504 DEADLINE_EXCEEDED, and if the model had already started answering, the SDK does not retry it. The API also answers 504 when the model sends nothing for 90 seconds. On a 504, stream the response, or lower max_tokens.
Reasoning
Every chat model reasons by default. The reasoning text arrives inreasoning_content, a field OpenAI’s format does not have, on the message or on stream deltas. Reasoning tokens count toward max_tokens and are billed as output. A reasoning model can spend all 4,096 tokens of the default bound reasoning and return finish_reason: length with no answer, so set max_tokens higher for long reasoning.
reasoning_effort takes the values in the model’s input_schema: minimal, low, medium, high, xhigh and max on every model, and none, which turns reasoning off, on every model except zai-org/glm-5.3 and zai-org/glm-5.3-flash. Hedra sends minimal to the model as low, medium as high and xhigh as max. Leaving it out uses the model’s default, which is max on moonshotai/kimi-k3.
Stream the response
Passstream: true. To get token counts, also pass stream_options: {"include_usage": true}: a chunk with empty choices then carries usage. Every content chunk arrives before it.
data: [DONE], when:
- the model fails or cuts the stream short (
codeUNAVAILABLE); - the stream reaches its 600-second limit, or the model sends nothing for 90 seconds (
DEADLINE_EXCEEDED); - Hedra fails while relaying it (
INTERNAL).
openai.APIError with the event’s message, code and type.
Request fields
The route accepts these top-level fields and answers any other with400 naming it:
model, messages, max_tokens, max_completion_tokens, n, stream, stream_options, store, tools, tool_choice, parallel_tool_calls, response_format, reasoning_effort, temperature, top_p, stop, seed, frequency_penalty, presence_penalty, logit_bias, logprobs, top_logprobs, user, safety_identifier and prompt_cache_key.
nmust be1.max_tokensandmax_completion_tokensboth bound the output, and the smaller one applies.response_formattakes{"type": "text"},{"type": "json_object"}or{"type": "json_schema", "json_schema": {...}}.stream_optionsrequiresstream: true.- Hedra doesn’t store completions, so
storemust befalseor left out. user,safety_identifierandprompt_cache_keyare accepted and ignored.- Messages take the roles
system,developer,user,assistantandtool. stopworks on every model.logprobs: trueandtop_logprobsreturn400: no model returns log probabilities.seedis accepted and passed to the model. It is best effort, as on OpenAI: in our tests only 1 of 50 same-seed pairs attemperature: 1returned the same text, andtemperature: 0alone repeated only onmoonshotai/kimi-k3anddeepseek-ai/deepseek-v4-pro-0813. Do not rely on either for reproducible output. Responses carry nosystem_fingerprint.frequency_penaltyandpresence_penaltydiscourage the model from repeating words.frequency_penaltyis accepted only at0onzai-org/glm-5.3,zai-org/glm-5.3-flash,deepseek-ai/deepseek-v4-pro-0813anddeepseek-ai/deepseek-v4.1-flash, which accept anypresence_penalty.moonshotai/kimi-k3acceptsfrequency_penaltyandpresence_penaltyonly at0.moonshotai/kimi-k3always calls tools in parallel, and returns400forparallel_tool_calls: false: leave it out.- A message’s
contentis a string or a list oftextandimage_urlparts. An image URL must behttps://or adata:URL. A model that does not take images, or a request with more images than the model accepts, returns400. - A request body over 45 MB,
data:images included, returns400withparambody.
Errors
Every error response, and every mid-stream error event, has the body every v3 route returns:code. type is OpenAI’s error type for the HTTP status, so that the SDK’s e.type is set. Every error response sets x-should-retry: true or false from retryable, and the SDK follows it. A retryable error also sets Retry-After, the number of seconds to wait before retrying.
The exception names are the Python SDK’s. The TypeScript SDK uses the same names, except that it raises a
402 as the base APIError. The exception holds the error object (e.body in Python, e.error in TypeScript) and the response’s X-Request-Id (e.request_id, e.requestID).
Billing and concurrency
Before sending a request, Hedra holds its largest possible price on your API wallet: an upper bound on the prompt’s tokens at the input price, plusmax_tokens at the output price. After the response it keeps the price of the tokens the model used and returns the rest. For a request with no max_tokens, Hedra holds the price of 4,096 output tokens, and a lower max_tokens lowers the hold. Hedra holds an amount for each request in flight, so 15 requests at once need 15 holds.
A 402 has two causes:
- The balance is too small for this request’s hold. The
402is not retryable: add funds, or lowermax_tokens. - Your own in-flight requests are holding the balance. The
402is retryable afterRetry-After, once those requests finish and return their unused holds.
429 with X-RateLimit-Concurrency-Limit, the cap, and X-RateLimit-Concurrency-Remaining: 0.
Look up a request
Each chat request is a job, and the completion’sid is its job id (job_<uuid>). GET /v3/jobs/{job_id} returns its status, error, net cost, token usage and timing, with an empty outputs.
Responses API
POST /v3/responses serves the same models in OpenAI’s Responses API format, with the same keys and billing. The response’s id is the request’s job id.
output items and the new message in input:
model, input, instructions, tools, tool_choice, parallel_tool_calls, reasoning, max_output_tokens, temperature, top_p, text, stream, store, include, prompt_cache_key, safety_identifier, user, service_tier and client_metadata.
- Hedra doesn’t store responses.
storemust befalseor left out, and a request that setsprevious_response_idorconversation, or sends anitem_referenceitem, returns400. Send the whole conversation ininput. toolstakesfunctiontools andnamespacetools. Hedra offers a namespace’s functions to the model as<namespace>__<name>, and returns a call to one with itsnamespaceandname.reasoning.efforttakes OpenAI’s values:minimalbecomeslow,mediumbecomes the model’s default effort, andxhighbecomesmax.- The model’s reasoning arrives as a
reasoningitem. Sending that item back ininputreturns the reasoning to the model. text.formattakestext,json_objectorjson_schema, asresponse_formatdoes, soclient.responses.parseworks. The route acceptstext.verbosityandservice_tierand ignores them.max_output_tokensbounds the output asmax_tokensdoes.- Without
max_output_tokens, output is limited to 32,768 tokens, or to the model’smax_output_tokensif that is lower, and a response that reaches the limit ends withstatus: "incomplete". stream: truestreams the response as Responses events, which the SDK’sclient.responses.streamreads.- Errors use the chat route’s body and codes (Errors).
Messages API
POST /v3/anthropic/v1/messages serves the same models in Anthropic’s Messages API format, with the same keys and billing. The Anthropic SDK appends /v1/messages to its base URL, so set the base URL to https://api.hedra.com/v3/anthropic. For a client that appends only /messages, such as the AI SDK’s @ai-sdk/anthropic provider, set the base URL to https://api.hedra.com/v3/anthropic/v1. The Anthropic SDK sends api_key as x-api-key; auth_token sends it as Authorization: Bearer, and both work. The message’s id is the request’s job id.
model, messages, max_tokens, system, tools, tool_choice, stop_sequences, temperature, top_p, stream, thinking, output_config, metadata and context_management, and answers any other field, such as top_k, with 400 naming it.
max_tokensis required, as on Anthropic’s API.toolstakes client tools, withname,descriptionandinput_schema. A server tool, such asweb_search_20250305, returns400.- The model’s reasoning arrives as a
thinkingblock with an emptysignature. Sending that block back inmessagesreturns the reasoning to the model. output_config.efforttakes Anthropic’s values,lowtomax, and sets the model’s reasoning effort.thinking: {"type": "disabled"}turns reasoning off, whichzai-org/glm-5.3andzai-org/glm-5.3-flashanswer with400: those models always reason.thinking.budget_tokens,cache_control,metadataandcontext_managementare accepted and ignored.- A
tool_resultblock’s images go to the model with the next user message, since a tool result holds text alone on the OpenAI format the models run on. A model that does not take images gets a note in their place. stream: truestreams the response as Messages events, which the SDK’sclient.messages.streamreads.usage.input_tokensleaves out the prompt tokens the model served from its cache, whichcache_read_input_tokenscounts, andusage.costis the request’s charge in US dollars.stop_reasonisend_turn,max_tokensortool_use;stop_sequenceis always null.- Errors use the chat route’s body and codes (Errors), and the SDK raises its exception for the status.
- There is no
POST /v1/messages/count_tokens.
Where Hedra differs from OpenAI
Fields other hosts accept
Other OpenAI-compatible hosts accept fields that return400 here. Remove them from your request: