Skip to content
Numes

API guides

API overview

Base URL, request format, endpoints, common headers and response basics for the Numes compatible API.

On this page

The Numes API follows the OpenAI Chat Completions shape and the OpenRouter API conventions, so most existing clients work after you change the base URL and key. This page covers what every request has in common. The endpoint pages in this tab are generated from the same OpenAPI contract the server is built against.

Base URL and versioning

Text
https://api.numes.ai/api/v1

The major version is part of the path (/api/v1). New optional response fields can appear at any time, so ignore response fields you don't recognize. Request objects are closed: a field the API doesn't implement is rejected, not ignored.

The contract is available as an OpenAPI 3.1 document at /docs/openapi.json; use it to generate a typed client.

Request format

  • JSON bodies. POST and PATCH routes take a JSON body with Content-Type: application/json; a body with another content type returns 415 unsupported_media_type. Transcriptions also accept multipart/form-data, and encrypted chat takes the SDK's encrypted body.

  • Closed request objects. An unknown field anywhere in the body, including inside provider, reasoning or response_format, returns 400 invalid_request. Parameters lists every accepted field.

  • null means omitted. Nullable fields such as temperature, max_tokens or stop treat null like leaving the field out.

  • Body size. Each route has a body limit, from 32 KiB for key management to 25 MiB for transcriptions. See Limits.

  • Encoding. Bodies are UTF-8. Timestamps are RFC 3339 strings, except where OpenAI compatibility requires Unix seconds (created).

  • Server-side only. Browser requests from third-party origins are rejected with 403 cors_forbidden. Call the API from your backend and keep keys out of browser code.

curl -X POST "https://api.numes.ai/api/v1/chat/completions" \  -H "Authorization: Bearer $NUMES_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "model": "openai/gpt-6-luna",    "messages": [      {        "role": "user",        "content": "Summarize the CAP theorem in one sentence."      }    ]  }'

Endpoints

MethodPathKeyPurpose
GET/modelsInferenceList models your key can use, priced in its currency
GET/models/{author}/{slug}/endpointsInferenceList the provider endpoints that serve one model
POST/chat/completionsInferenceChat completion, buffered or streamed
GET/generationInferenceUsage and cost of one request
POST/e2ee/resolveInferenceResolve an encrypted model before encrypting a request
POST/e2ee/chat/completionsInferenceEncrypted chat completion, sent through an SDK
POST/embeddingsInferenceText and multimodal embeddings
POST/imagesInferenceImage generation, buffered or streamed
POST/audio/speechInferenceText to speech, streamed audio bytes
POST/audio/transcriptionsInferenceSpeech to text
GET/keyEitherMetadata, limit and usage of the calling key
GET/keysManagementList inference keys
POST/keysManagementCreate an inference key
GET/keys/{hash}ManagementGet one inference key
PATCH/keys/{hash}ManagementRename, disable or change the limit of a key
DELETE/keys/{hash}ManagementDelete a key
GET/creditsManagementCredits and usage totals in one currency

Paths are relative to https://api.numes.ai/api/v1. Authentication explains the two key kinds.

An unknown path returns a plain 404, and a known path with the wrong method returns 405 with an Allow header. Neither uses the JSON error envelope.

Common headers

Request headers

HeaderApplies toBehavior
AuthorizationAll routesBearer <key>. Required. See Authentication.
Content-TypePOST, PATCHapplication/json, or multipart/form-data for transcriptions.
X-Request-IdAll routesOptional correlation ID, 1–128 characters from A-Z a-z 0-9 . _ -. Must be unique per request in your account.
X-Session-IdChatOptional sticky-routing key, at most 256 characters. A body session_id takes precedence.
X-OpenRouter-MetadataChatenabled or true adds openrouter_metadata to the response.
HTTP-RefererInference routesOptional. Groups your traffic by app in Activity. Only the public origin is kept.
X-TitleInference routesAccepted for compatibility and ignored.

X-Request-Id. A valid value is used as sent; otherwise the API generates a 32-character hex ID. On inference routes the ID is recorded with the request, and reusing an ID already recorded in your account returns 400 invalid_request, even for a retry of a failed request. It isn't an idempotency key: send a fresh ID on every call, including retries, or omit the header. See Request and generation IDs.

X-OpenRouter-Metadata. The value is case-insensitive; anything other than enabled or true opts out. X-OpenRouter-Experimental-Metadata is accepted as an alias; when both are sent, X-OpenRouter-Metadata wins. Buffered chat responses and the usage chunk of a stream then include:

JSON
{  "openrouter_metadata": {    "generation_id": "0f5b5c9a-3a7e-4c6f-9d7b-2e1f0a6b8c4d",    "request_id": "checkout-summary-7f3a",    "outcome": "success",    "cancelled": false,    "delivered_output": true,    "provider": "Example Provider",    "provider_slug": "example-provider",    "endpoint": "example-provider/primary"  }}

Response headers

HeaderBehavior
X-Request-IdYour value or a generated one, on every response. Quote it when you contact support.
X-Generation-IdThe generation ID, on inference responses once output starts. Pass it to GET /generation.
Retry-AfterWhole seconds to wait, on 429 rate_limited responses from your rate limits or from repeated failed authentications.
Cache-Controlno-store on JSON responses, no-cache on event streams.

Responses

A buffered chat completion returns one JSON object; the Create chat completion reference lists every field. choices always has exactly one entry; there's no n parameter. Streams carry the same data as a sequence of chunks; see Streaming.

Finish reasons

finish_reasonMeaning
stopThe model finished or hit a stop sequence. Also used when the provider reports no reason.
lengthThe output reached the output limit or a reasoning limit.
tool_callsThe model stopped to call one or more tools. Some endpoints report stop instead, so check for tool calls too.
content_filterThe provider filtered the output.
otherThe provider reported a reason with no standard mapping.
errorStreams only: the stream ended with an in-band error.

Treat any other value as a normal completion.

Look up cost and stats

Every buffered response includes usage with the request's cost, and every successful stream ends with a usage chunk. For the authoritative record, for example after a dropped connection, pass the generation ID from the X-Generation-Id header or the response id to GET /generation. Usage accounting explains each usage field.

Money

Every inference key has one billing currency, USD or BTC, fixed when the key is created. All prices, costs and limits the API returns for that key are in that currency, and there's no conversion between currencies.

FieldRepresentation
pricing in /models and the endpoints listExact decimal strings per unit (per token for text), for example "0.0000004"
usage.cost, total_cost, key limit and usageJSON numbers written from exact decimals, for example 0.000007
provider.max_priceJSON numbers per unit, in the key's currency
  • USD amounts are dollars.

  • BTC amounts are satoshis, not bitcoin: 1 means one satoshi, and costs can be fractional satoshis.

  • JSON numbers are exact as written, but most parsers read them as binary floats. Parse costs as decimals before adding them, for example json.loads(body, parse_float=Decimal) in Python.

Next steps