Skip to content
docs/api-referenceResources

API Reference

Every route on the platform, with its parameters, a runnable request and what comes back.

Every route, in one page. The endpoint headers elsewhere in these docs and the blocks below read from the same definition, so a route cannot be described as live on one page and planned on another. The cURL, JavaScript and Python snippets are generated from the sample body shown beneath each route. They are the request, not a paraphrase of it.

Conventions

ASPECTVALUE
Base URLhttps://api.routehook.ai/v1
AuthenticationAuthorization: Bearer <key>
Anthropic routex-api-key is accepted on POST /v1/messages
Request encodingapplication/json
Response encodingapplication/json, or text/event-stream when streaming
IdempotencyIdempotency-Key on a queue submit returns the existing job
Errors{ error: { code, message, request_id } }

GET/v1/keyAvailable

Describe the key making the call: its label, spend cap, lifetime usage and rate limit.

The route describes the key that called it. There is no way to read another key with this one. limit_reset, is_management_key and byok_usage are published as explicit constants rather than omitted. A client reading them gets a definite answer instead of a missing key it cannot tell from a typo. key_id is the key's own id, unprefixed; it is the id the dashboard shows and the one to quote in a support report.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/key \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": {
    "label": "Production",
    "limit": null,
    "usage": 128.4419,
    "limit_remaining": null,
    "is_provisioning_key": false,
    "is_free_tier": false,
    "rate_limit": { "requests": 600, "interval": "60s" },
    "limit_reset": null,
    "is_management_key": false,
    "byok_usage": 0,
    "key_id": "3xK9mQ2p7vL4nR8t",
    "account_id": "acct_9f2c41be",
    "created_at": "2026-05-01T09:14:22Z",
    "last_used_at": "2026-08-23T11:02:47Z",
    "expires_at": null
  }
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

GET/v1/creditsAvailable

Read the account balance, the amount held by requests in flight and what is left to spend.

Figures here are JSON numbers, rounded to two decimal places. Per-token *rates* elsewhere are strings. See /docs/pricing for why.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/credits \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": {
    "total_credits": 250.0,
    "total_usage": 128.44,
    "balance": 121.56,
    "held": 0.42,
    "available": 121.14,
    "credit_limit": 0,
    "currency": "USD"
  }
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

GET/v1/generationAvailable

Read what one request cost and how long it took.

reference_value is what the same call costs at the vendor's list price. It is the only number here you have to compare against; what the platform pays upstream is never published.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
idstringrequired-The request id returned in the X-Routehook-Request-Id header, or on an error body.

Request

cURL
curl https://api.routehook.ai/v1/generation?id=req_7c41d9be \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": {
    "id": "req_7c41d9be",
    "model": "openai/gpt-4o-mini",
    "streamed": false,
    "generation_time": 812,
    "created_at": "2026-08-23T11:02:47Z",
    "tokens_prompt": 9,
    "tokens_completion": 8,
    "native_tokens_prompt": 9,
    "native_tokens_completion": 8,
    "num_media_prompt": 0,
    "num_media_completion": 0,
    "origin": "api",
    "usage": 0.000103,
    "total_cost": 0.000103,
    "cache_discount": 0,
    "finish_reason": "stop",
    "latency": 812,
    "moderation_latency": 0,
    "request_id": "req_7c41d9be",
    "status": "succeeded",
    "error_code": null,
    "attempts": 1,
    "fallback_used": false,
    "reference_value": 0.000245
  }
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

POST/v1/chat/completionsAvailable

Chat completions in OpenAI's shape, streamed or whole, with automatic failover.

Unknown request fields are forwarded upstream rather than refused, so a vendor parameter this gateway has never heard of still works.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
messagesarrayrequired-Ordered turns, each with a role of system, user or assistant, and content.
streambooleanoptionalfalseEmit server-sent events instead of one body. See /docs/streaming.
max_tokensintegeroptionalmodel defaultCeiling on generated tokens. Caps the output side of the bill.
temperaturenumberoptionalmodel defaultSampling randomness. Forwarded upstream unchanged.

Request

cURL
curl -X POST https://api.routehook.ai/v1/chat/completions \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "messages": [
      {
        "role": "user",
        "content": "Hello"
      }
    ]
  }'

Response

JSON200 OK
{
  "id": "chatcmpl_5f81c0",
  "object": "chat.completion",
  "created": 1786312455,
  "model": "openai/gpt-4o-mini",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Hello. How can I help?" },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 8,
    "total_tokens": 17,
    "cost": "0.000103"
  }
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/completionsAvailable

OpenAI's legacy prompt completion, translated onto the same routing as chat.

Almost nothing upstream still serves a true completion endpoint. The prompt is wrapped as one user message on the way out and the message content unwrapped back to text on the way in.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
promptstring | string[]required-The prompt, or a batch of them. A batch answers with one choice per prompt, in order.
max_tokensintegeroptionalmodel defaultCeiling on generated tokens.
streambooleanoptionalfalseEmit server-sent events instead of one body.
temperaturenumberoptionalmodel defaultSampling randomness. Forwarded upstream unchanged.

Request

cURL
curl -X POST https://api.routehook.ai/v1/completions \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "prompt": "Write one sentence about harbour fog.",
    "max_tokens": 64
  }'

Response

JSON200 OK
{
  "id": "cmpl_5f81c0",
  "object": "text_completion",
  "created": 1786312455,
  "model": "openai/gpt-4o-mini",
  "choices": [
    {
      "index": 0,
      "text": "Fog rolled off the water and swallowed the cranes one by one.",
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 8,
    "completion_tokens": 14,
    "total_tokens": 22,
    "cost": "0.0000038"
  }
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/messagesAvailable

Anthropic's Messages API, so an Anthropic client works against this base URL unchanged.

The key may arrive as x-api-key as well as a bearer token, so an Anthropic client needs no header rewriting. model on the way back is the gateway slug, never the upstream's.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
messagesarrayrequired-Anthropic's turns. Role user or assistant, and content.
max_tokensintegerrequired-Required by the Messages API, unlike chat completions. There is no default to fall back on.
systemstringoptional-System prompt, sent apart from the turns.
streambooleanoptionalfalseEmit Anthropic's event framing: message_start through message_stop.
stop_sequencesstring[]optional-Strings that end generation when produced.
toolsarrayoptional-Tool definitions, in Anthropic's schema.

Request

cURL
curl -X POST https://api.routehook.ai/v1/messages \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4",
    "max_tokens": 256,
    "messages": [
      {
        "role": "user",
        "content": "Hello"
      }
    ]
  }'

Response

JSON200 OK
{
  "id": "msg_5f81c0",
  "type": "message",
  "role": "assistant",
  "model": "anthropic/claude-sonnet-4",
  "content": [{ "type": "text", "text": "Hello. How can I help?" }],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": { "input_tokens": 9, "output_tokens": 8 }
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/images/generationsAvailable

Generate images and return their URLs. The connection is held until the images exist.

The connection is held for the 20–60 seconds a generation takes. Video cannot work this way. Use the queue. Batching with n is a latency optimisation, not a discount.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
promptstringrequired-What to generate. Up to 32,000 characters.
nintegeroptional1Images per request, 1 to 10. Each bills at the unit rate.
sizestringoptionalmodel defaultDimensions (1024x1024) or an aspect ratio (16:9). Advisory. Translated to whatever the model expects.
reference_urlsstring[]optional-Publicly reachable input images, for models that take references. Ignored by models that do not.

Request

cURL
curl -X POST https://api.routehook.ai/v1/images/generations \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/nano-banana-2",
    "prompt": "isometric factory floor, technical illustration",
    "size": "1024x1024",
    "n": 2
  }'

Response

JSON200 OK
{
  "created": 1786312455,
  "model": "google/nano-banana-2",
  "data": [
    { "url": "https://cdn.routehook.ai/img/9d21f4-0.png" },
    { "url": "https://cdn.routehook.ai/img/9d21f4-1.png" }
  ]
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/imagesAvailable

The same image generation under OpenRouter's path. One handler, one bill.

The same handler as POST /v1/images/generations, at OpenRouter's spelling of the path. One implementation, one bill, one response shape. Which of the two you call is a matter of which client library you already have.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
promptstringrequired-What to generate. Up to 32,000 characters.
nintegeroptional1Images per request, 1 to 10. Each bills at the unit rate.
sizestringoptionalmodel defaultDimensions (1024x1024) or an aspect ratio (16:9). Advisory. Translated to whatever the model expects.
reference_urlsstring[]optional-Publicly reachable input images, for models that take references. Ignored by models that do not.

Request

cURL
curl -X POST https://api.routehook.ai/v1/images \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/nano-banana-2",
    "prompt": "isometric factory floor, technical illustration",
    "size": "1024x1024",
    "n": 2
  }'

Response

JSON200 OK
{
  "created": 1786312455,
  "model": "google/nano-banana-2",
  "data": [
    { "url": "https://cdn.routehook.ai/img/9d21f4-0.png" },
    { "url": "https://cdn.routehook.ai/img/9d21f4-1.png" }
  ]
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/embeddingsAvailable

Turn text into vectors for search, clustering and retrieval.

Only models in the embedding category are accepted; anything else is refused with invalid_request before a hold is taken. Vectors are truncated in this example. Real ones are the model's full width.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
inputstring | string[] | number[][]required-One string, a batch of strings, or pre-tokenised input to embed in a single call.
encoding_formatfloat | base64optionalfloatHow each vector is encoded in the response.
dimensionsintegeroptionalmodel defaultTruncate vectors to this width, where the model supports it.
userstringoptional-Opaque end-user identifier, forwarded upstream.

Request

cURL
curl -X POST https://api.routehook.ai/v1/embeddings \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/text-embedding-3-small",
    "input": [
      "first document",
      "second document"
    ]
  }'

Response

JSON200 OK
{
  "object": "list",
  "model": "openai/text-embedding-3-small",
  "data": [
    { "object": "embedding", "index": 0, "embedding": [0.0021, -0.0138, 0.0074] },
    { "object": "embedding", "index": 1, "embedding": [0.0019, -0.0142, 0.0069] }
  ],
  "usage": { "prompt_tokens": 6, "total_tokens": 6 }
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/responsesAvailable

OpenAI's Responses API, served by every text model on the platform rather than one vendor's.

Translated onto a chat completion rather than forwarded, so every text model in the catalogue answers here, not only the one vendor that implements this route. previous_response_id is refused rather than ignored: this gateway stores no conversations, and a reply that had silently forgotten the earlier turns would be worse than an error saying so.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
inputstring | object[]required-A prompt, or the conversation so far as a list of role/content items.
instructionsstringoptional-The system prompt. Sent as its own turn, not folded into the first user message.
max_output_tokensintegeroptionalmodel defaultCeiling on the answer.
streambooleanoptionalfalseEmit the answer as server-sent events.
toolsobject[]optional-Function definitions, in the same shape chat takes.
tool_choicestring | objectoptional-auto, none, required, or a named function.
parallel_tool_callsbooleanoptional-Allow more than one tool call in a single turn.
temperaturenumberoptional-0 to 2. Forwarded unchanged.
top_pnumberoptional-0 to 1. Forwarded unchanged.
metadataobjectoptional-Echoed back on the response object rather than forwarded upstream. It changes neither routing nor price.
storebooleanoptional-Accepted and ignored. This gateway stores no conversations, so there is nothing for it to switch on.
previous_response_idstringoptional-Refused with 400 rather than ignored, for the reason in the note below.
userstringoptional-An opaque end-user id, forwarded upstream.

Request

cURL
curl -X POST https://api.routehook.ai/v1/responses \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "input": "Say exactly: parity works",
    "max_output_tokens": 20
  }'

Response

JSON200 OK
{
  "id": "resp_A81FB265",
  "object": "response",
  "created_at": 1787654321,
  "status": "completed",
  "error": null,
  "incomplete_details": null,
  "model": "openai/gpt-4o-mini",
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [{ "type": "output_text", "text": "parity works", "annotations": [] }]
    }
  ],
  "output_text": "parity works",
  "instructions": null,
  "max_output_tokens": 20,
  "temperature": null,
  "top_p": null,
  "parallel_tool_calls": true,
  "tool_choice": "auto",
  "tools": [],
  "metadata": {},
  "usage": { "input_tokens": 12, "output_tokens": 3, "total_tokens": 15 }
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/audio/speechAvailable

Turn text into spoken audio and stream the bytes back.

The response is audio, not JSON. The bytes are streamed rather than buffered, so a long document does not sit in memory on either side. Billing is per character of input, and the charge is on X-Routehook-Cost because there is no body to put it in.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
inputstringrequired-The text to speak. Capped at 4096 characters, which is also the axis this route is billed on.
voicestringoptionalalloyVendor voice id. Not an enum here. A new voice should not need a release from us to be usable.
response_formatmp3 | opus | aac | flac | wav | pcmoptionalmp3Container for the returned audio.
speednumberoptional1.0Playback rate, 0.25 to 4.0.

Request

cURL
curl -X POST https://api.routehook.ai/v1/audio/speech \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/tts-1",
    "input": "Routehook audio is live.",
    "voice": "alloy"
  }'

Response

JSON200 OK
HTTP/1.1 200 OK
Content-Type: audio/mpeg
X-Routehook-Cost: 0.00045

<binary audio>

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/audio/transcriptionsAvailable

Transcribe audio to text, with optional word and segment timestamps.

Billed per second of audio. Where a duration is reported that number is used; where it is not, the upload is measured and the request row records that the figure was estimated rather than metered.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
input_audioobjectrequired-`{ data, format }`: base64 audio, with or without a data: prefix, and the container it is in.
languagestringoptional-ISO-639-1 hint. Improves both accuracy and latency when it is known.
response_formatjson | text | srt | verbose_json | vttoptionaljsonShape of the transcript. Non-JSON formats are returned verbatim.
timestamp_granularitiesstring[]optional-`word` and/or `segment`. Only meaningful with verbose_json.

Request

cURL
curl -X POST https://api.routehook.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-transcribe",
    "input_audio": {
      "data": "UklGRiQAAABXQVZF...",
      "format": "mp3"
    }
  }'

Response

JSON200 OK
{
  "text": "Routehook audio is live."
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/rerankAvailable

Score a set of documents against a query and return them in relevance order.

index is the position in the request's document list, not in this response, so a reordered result still points at what you sent. Billed on the query plus the documents.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Model slug, as returned by GET /v1/models.
querystringrequired-What the documents are being scored against.
documentsstring[] | object[]required-Up to 1000 documents, as plain strings or as objects carrying a `text` field.
top_nintegeroptionalallReturn only the highest-scoring N.
return_documentsbooleanoptionalfalseEcho each document back beside its score.

Request

cURL
curl -X POST https://api.routehook.ai/v1/rerank \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "cohere/rerank-v3.5",
    "query": "how do holds work",
    "documents": [
      "A hold reserves the ceiling before the call.",
      "Invoices are issued monthly."
    ],
    "top_n": 2
  }'

Response

JSON200 OK
{
  "id": "req_9f2c41be",
  "model": "cohere/rerank-v3.5",
  "results": [
    { "index": 0, "relevance_score": 0.97 },
    { "index": 1, "relevance_score": 0.04 }
  ],
  "usage": { "total_tokens": 24 }
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/queue/{model}Available

Submit a job and return immediately with the id and the URLs that follow it.

Everything in the body other than the fields above is the model's own input and is passed through. Money is held at submit and settled when the job reaches a terminal state.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Path parameter, and a wildcard. The whole slug, slashes included.
webhook_urlstringoptional-https URL to POST the terminal state to. `?fal_webhook=` is accepted for the same purpose.
promptstringoptional-Up to 32,000 characters. Read by the gateway for the request record, and forwarded.
nintegeroptional-1 to 10. Multiplies the reservation and the bill.
sizestringoptional-Vendor size string, forwarded as sent.
durationnumberoptional-Seconds, 1 to 600. The axis a video model is billed on, so it also sizes the hold.
Idempotency-Keyheaderoptional-Repeating a submit with the same key returns the existing job instead of opening a second one.

Request

cURL
curl -X POST https://api.routehook.ai/v1/queue/fal/veo3 \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "drone shot over a harbour at dawn",
    "duration": 5,
    "webhook_url": "https://your.app/hooks/routehook"
  }'

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "status": "IN_QUEUE",
  "queue_position": 3,
  "status_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34/status",
  "response_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34",
  "cancel_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34/cancel"
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

GET/v1/queue/requests/{job_id}/statusAvailable

Poll a job: queue position, terminal outcome, timings and optional logs.

status carries fal's three values only (IN_QUEUE, IN_PROGRESS, COMPLETED), so a client polling until COMPLETED terminates. A job that failed or was cancelled is COMPLETED here and says which in outcome. queue_position is null once the job has left the queue rather than 0, because a running job reporting 0 reads as about to start. metrics is in seconds. Fal's unit, and the one place this API does not suffix a duration _ms. GET /v1/queue/{model}/requests/{job_id}/status is the same handler.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
job_idstringrequired-Path parameter. The request_id returned by the submit call.
logs0 | 1optional0Include the job's log lines in the response.

Request

cURL
curl https://api.routehook.ai/v1/queue/requests/job_ab12cd34/status?logs=1 \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "status": "IN_PROGRESS",
  "outcome": null,
  "queue_position": null,
  "logs": [
    { "message": "sampling frame 12/120", "level": "INFO", "timestamp": "2026-08-23T11:02:47Z" }
  ],
  "metrics": { "inference_time": null, "queue_time": 4.1 },
  "error": null
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

GET/v1/queue/requests/{job_id}Available

Fetch the output of a finished job.

Check the status code. While the job is still running this route answers 202 with the status body — request_id, status, queue_position — not with the result above; 200 means finished. A client that parses the body without looking at the code reads a running job as a result with no payload. payload is the upstream's own result body, forwarded verbatim rather than normalised, so there is one shape per model. A job that failed answers with the standard error envelope and the failure's status code, not with a 200 carrying an error field. GET /v1/queue/{model}/requests/{job_id} is the same handler.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
job_idstringrequired-Path parameter. The request_id returned by the submit call.

Request

cURL
curl https://api.routehook.ai/v1/queue/requests/job_ab12cd34 \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "model": "fal/veo3",
  "created": 1786312455,
  "outcome": "succeeded",
  "payload": {
    "video": { "url": "https://cdn.routehook.ai/vid/ab12cd34.mp4" }
  },
  "gateway_request_id": "req_7c41d9be",
  "cost": "0.7500",
  "reference_value": "1.5000",
  "usage": { "video_seconds": "5" }
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

PUT/v1/queue/requests/{job_id}/cancelAvailable

Cancel a job that has not finished and release its hold.

Cancelling releases the hold. The call is idempotent and answers 200 even for a job that had already finished: canceled is false there, and exists for the audit trail rather than for control flow. outcome is null in the window between the cancellation being recorded and the worker abandoning an attempt already in flight upstream.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
job_idstringrequired-Path parameter. The request_id returned by the submit call.

Request

cURL
curl -X PUT https://api.routehook.ai/v1/queue/requests/job_ab12cd34/cancel \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "status": "COMPLETED",
  "outcome": "canceled",
  "canceled": true
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

GET/v1/queue/requests/{job_id}/streamAvailable

Server-sent stream of a job's status transitions, instead of polling.

The response is text/event-stream; the object above is one event's data: payload. The stream ends when the job reaches a terminal state. Use it instead of a polling loop, not alongside one.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
job_idstringrequired-Path parameter. The request_id returned by the submit call.

Request

cURL
curl https://api.routehook.ai/v1/queue/requests/job_ab12cd34/stream \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "status": "IN_PROGRESS",
  "outcome": null,
  "queue_position": 0
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

GET/v1/queue/{model}/requests/{job_id}/statusAvailable

The same poll, at fal's URL shape. The model segment is ignored.

fal's path shape for GET /v1/queue/requests/{job_id}/status, reaching the same handler. It exists so a client that kept fal's URLs works without rewriting them; a new integration should use the short form.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Path parameter, and a wildcard. Matched and then ignored — the job id alone identifies the job, and any slug here is accepted.
job_idstringrequired-Path parameter. The request_id returned by the submit call.
logs0 | 1optional0Include the job's log lines in the response.

Request

cURL
curl https://api.routehook.ai/v1/queue/fal/veo3/requests/job_ab12cd34/status?logs=1 \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "status": "IN_PROGRESS",
  "outcome": null,
  "queue_position": null,
  "logs": [
    { "message": "sampling frame 12/120", "level": "INFO", "timestamp": "2026-08-23T11:02:47Z" }
  ],
  "metrics": { "inference_time": null, "queue_time": 4.1 },
  "error": null
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

GET/v1/queue/{model}/requests/{job_id}Available

The same result, at fal's URL shape.

fal's path shape for GET /v1/queue/requests/{job_id}, reaching the same handler — including the 202 while the job is still running. It exists so a client that kept fal's URLs works without rewriting them; a new integration should use the short form.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Path parameter, and a wildcard. Matched and then ignored — the job id alone identifies the job, and any slug here is accepted.
job_idstringrequired-Path parameter. The request_id returned by the submit call.

Request

cURL
curl https://api.routehook.ai/v1/queue/fal/veo3/requests/job_ab12cd34 \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "model": "fal/veo3",
  "created": 1786312455,
  "outcome": "succeeded",
  "payload": {
    "video": { "url": "https://cdn.routehook.ai/vid/ab12cd34.mp4" }
  },
  "gateway_request_id": "req_7c41d9be",
  "cost": "0.7500",
  "reference_value": "1.5000",
  "usage": { "video_seconds": "5" }
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

PUT/v1/queue/{model}/requests/{job_id}/cancelAvailable

The same cancel, at fal's URL shape.

fal's path shape for PUT /v1/queue/requests/{job_id}/cancel, reaching the same handler. It exists so a client that kept fal's URLs works without rewriting them; a new integration should use the short form.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Path parameter, and a wildcard. Matched and then ignored — the job id alone identifies the job, and any slug here is accepted.
job_idstringrequired-Path parameter. The request_id returned by the submit call.

Request

cURL
curl -X PUT https://api.routehook.ai/v1/queue/fal/veo3/requests/job_ab12cd34/cancel \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "status": "COMPLETED",
  "outcome": "canceled",
  "canceled": true
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

POST/v1/run/{model}Available

Submit a job and hold the connection until it finishes or the wait ceiling is reached.

Identical to submitting and polling, with the wait done for you. Past the platform's wait ceiling the call returns the job so you can poll it. The work is not thrown away.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Path parameter, and a wildcard. The whole slug, slashes included.

Request

cURL
curl -X POST https://api.routehook.ai/v1/run/fal/veo3 \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "drone shot over a harbour at dawn",
    "duration": 5
  }'

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "model": "fal/veo3",
  "created": 1786312455,
  "outcome": "succeeded",
  "payload": {
    "video": { "url": "https://cdn.routehook.ai/vid/ab12cd34.mp4" }
  },
  "gateway_request_id": "req_7c41d9be",
  "cost": "0.7500",
  "reference_value": "1.5000",
  "usage": { "video_seconds": "5" }
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/videos/generationsAvailable

Submit a video generation and get a job id back. Answers 202: the work runs for minutes.

202, not 200. The name looks synchronous and the behaviour is not: video generation runs for minutes and no connection is held for it. Poll status_url, or GET /v1/videos/{job_id}, which is the same job under a shorter path. Everything in the body other than the fields above is the model's own input and is forwarded untouched.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Body field, not a path segment. This route has none to carry it, unlike POST /v1/queue/{model}.
promptstringoptional-Up to 32,000 characters. Read by the gateway for the request record, and forwarded.
durationnumberoptional-Seconds, 1 to 600. The axis a video model is billed on, so it also sizes the hold.
sizestringoptional-Vendor size string, forwarded as sent.
nintegeroptional-1 to 10. Multiplies the reservation and the bill.
webhook_urlstringoptional-https URL to POST the terminal state to. `?fal_webhook=` is accepted for the same purpose.
Idempotency-Keyheaderoptional-Repeating a submit with the same key returns the existing job instead of opening a second one.

Request

cURL
curl -X POST https://api.routehook.ai/v1/videos/generations \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "fal/veo3",
    "prompt": "drone shot over a harbour at dawn",
    "duration": 5
  }'

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "status": "IN_QUEUE",
  "queue_position": 3,
  "status_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34/status",
  "response_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34",
  "cancel_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34/cancel"
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

POST/v1/videosAvailable

The same submit under OpenRouter's path.

The same handler as POST /v1/videos/generations, at OpenRouter's spelling of the path. 202, not 200 — poll status_url or GET /v1/videos/{job_id}.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
modelstringrequired-Body field, not a path segment. This route has none to carry it, unlike POST /v1/queue/{model}.
promptstringoptional-Up to 32,000 characters. Read by the gateway for the request record, and forwarded.
durationnumberoptional-Seconds, 1 to 600. The axis a video model is billed on, so it also sizes the hold.
sizestringoptional-Vendor size string, forwarded as sent.
nintegeroptional-1 to 10. Multiplies the reservation and the bill.
webhook_urlstringoptional-https URL to POST the terminal state to. `?fal_webhook=` is accepted for the same purpose.
Idempotency-Keyheaderoptional-Repeating a submit with the same key returns the existing job instead of opening a second one.

Request

cURL
curl -X POST https://api.routehook.ai/v1/videos \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "fal/veo3",
    "prompt": "drone shot over a harbour at dawn",
    "duration": 5
  }'

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "status": "IN_QUEUE",
  "queue_position": 3,
  "status_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34/status",
  "response_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34",
  "cancel_url": "https://api.routehook.ai/v1/queue/requests/job_ab12cd34/cancel"
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
409model_unavailableModel is listed but has no live endpoint to route to.

GET/v1/videos/{job_id}Available

Poll a video job: its status while it runs, its result once it finishes.

The queue's result route under a shorter path, and the same handler. While the job is running it answers 202 with the status body — request_id, status, queue_position — and once it finishes, 200 with the result above. Poll it until the status code changes. The finished video's bytes are at GET /v1/videos/{job_id}/content.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
job_idstringrequired-Path parameter. The request_id returned by the submit call.

Request

cURL
curl https://api.routehook.ai/v1/videos/job_ab12cd34 \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "request_id": "job_ab12cd34",
  "model": "fal/veo3",
  "created": 1786312455,
  "outcome": "succeeded",
  "payload": {
    "video": { "url": "https://cdn.routehook.ai/vid/ab12cd34.mp4" }
  },
  "gateway_request_id": "req_7c41d9be",
  "cost": "0.7500",
  "reference_value": "1.5000",
  "usage": { "video_seconds": "5" }
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.
429rate_limitedBack off using the Retry-After header.

GET/v1/videos/{job_id}/contentAvailable

Stream the finished video's bytes.

The same proxy as GET /v1/files/{id}, reached by job id instead of by media reference. A job that has not finished answers 400 rather than 404: the bytes are on their way, and a client told 'not found' would stop polling.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/videos/job_ab12cd34/content \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
HTTP/1.1 200 OK
Content-Type: video/mp4
Accept-Ranges: bytes

<binary media>

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404not_foundNo such id, or it belongs to another account.
429rate_limitedBack off using the Retry-After header.
410goneThe reference expired. Permanent. Do not retry.

GET/v1/files/{id}Available

Fetch generated media by reference. Proxied at request time, never redirected upstream.

The origin copy is fetched at request time and streamed through. It never redirects: a 302 would publish the upstream URL, which is the one thing the indirection exists to hide. References expire in minutes, and an expired one answers 410 rather than a retryable code.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/files/file_9f2c41be \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
HTTP/1.1 200 OK
Content-Type: video/mp4
Accept-Ranges: bytes
Cache-Control: private, max-age=280, must-revalidate

<binary media>

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
404not_foundNo such id, or it belongs to another account.
429rate_limitedBack off using the Retry-After header.
410goneThe reference expired. Permanent. Do not retry.

GET/v1/jobsAvailable

List this account's jobs, newest first, keyset-paged.

This route is ours rather than fal's (fal has no job list), so it is the one place to find a job whose id was lost. A row carries no payload: fifty jobs' worth of upstream JSON is a megabyte of response to render a table, so the output stays behind response_url. cost is null until the hold is settled. An open job has been reserved against, not charged.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
statusstringoptionalallFilter to queued, running, succeeded, failed or canceled. The stored vocabulary, not the three wire statuses.
modelstringoptionalallFilter to one model slug, matched exactly.
categorystringoptionalallFilter to one modality: text, image, video, audio, embedding or rerank.
cursorstringoptional-Keyset cursor. The `next_cursor` value from the previous page.
limitintegeroptional50Rows per page, 1 to 200.

Request

cURL
curl https://api.routehook.ai/v1/jobs?limit=50&status=running \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": [
    {
      "request_id": "job_ab12cd34",
      "model": "fal/veo3",
      "category": "video",
      "status": "IN_PROGRESS",
      "outcome": null,
      "queue_position": null,
      "gateway_request_id": "req_7c41d9be",
      "cost": null,
      "error_code": null,
      "created_at": "2026-08-23T11:02:47Z",
      "started_at": "2026-08-23T11:02:51Z",
      "completed_at": null
    }
  ],
  "next_cursor": null
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
429rate_limitedBack off using the Retry-After header.

GET/v1/modelsAvailable

Every model with its category, status, published price and per-token rates.

Anonymous and cached, no key needed. Per-token rates are strings, because a client that sums a million float64 rates drifts. The headline price stays a number.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/models \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": [
    {
      "id": "openai/gpt-4o-mini",
      "canonical_slug": "openai/gpt-4o-mini",
      "name": "GPT-4o mini",
      "category": "text",
      "status": "available",
      "unit": "per 1M tokens",
      "price": 0.15,
      "reference_price": 0.30,
      "context_length": 128000,
      "pricing": {
        "prompt": "0.00000015",
        "completion": "0.0000006",
        "request": null,
        "image": null
      },
      "supported_parameters": ["tools", "temperature", "max_tokens"]
    }
  ]
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.

GET/v1/models/countAvailable

How many models are servable right now.

Counts models whose status is available. Everything listed but not yet servable — coming_soon — is excluded, so this is the number of slugs a request can actually route to rather than the length of GET /v1/models.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/models/count \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": { "count": 214 }
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.

GET/v1/models/userAvailable

The catalogue as this caller sees it.

Returns the same catalogue as GET /v1/models. OpenRouter narrows this route by an account's provider preferences; there is no such per-account filtering here — every published model is available to every key — so the honest answer is the whole catalogue rather than a stub. The route exists so a client that calls it gets a catalogue instead of a 404, and it will narrow on its own the day per-account preferences do.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/models/user \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": [
    {
      "id": "openai/gpt-4o-mini",
      "canonical_slug": "openai/gpt-4o-mini",
      "name": "GPT-4o mini",
      "category": "text",
      "status": "available",
      "unit": "per 1M tokens",
      "price": 0.15,
      "reference_price": 0.30,
      "context_length": 128000,
      "pricing": {
        "prompt": "0.00000015",
        "completion": "0.0000006",
        "request": null,
        "image": null
      },
      "supported_parameters": ["tools", "temperature", "max_tokens"]
    }
  ]
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.

GET/v1/model/{author}/{slug}Available

One model by slug. Singular 'model'. OpenRouter's spelling for this route.

Singular model, which is OpenRouter's spelling for this route and not a typo for the plural one. An unknown slug answers 404 with model_unavailable rather than not_found — note the code, and see the header of this file for why the two differ.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
author/slugstringrequired-Path parameter, and two segments. Catalogue slugs are namespaced, so `openai/gpt-4o-mini` is the whole of it.

Request

cURL
curl https://api.routehook.ai/v1/model/openai/gpt-4o-mini \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": {
    "id": "openai/gpt-4o-mini",
    "canonical_slug": "openai/gpt-4o-mini",
    "name": "GPT-4o mini",
    "category": "text",
    "status": "available",
    "unit": "per 1M tokens",
    "price": 0.15,
    "reference_price": 0.30,
    "context_length": 128000,
    "architecture": {
      "modality": "text->text",
      "input_modalities": ["text"],
      "output_modalities": ["text"],
      "tokenizer": null,
      "instruct_type": null
    },
    "pricing": {
      "prompt": "0.00000015",
      "completion": "0.0000006",
      "request": null,
      "image": null
    },
    "supported_parameters": ["tools", "temperature", "max_tokens"],
    "alias_target": null,
    "reasoning": { "supported": false },
    "discount": null
  }
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.
404model_unavailableNo such id, or it belongs to another account. Note the code. This route does not answer not_found.

GET/v1/embeddings/modelsAvailable

The catalogue narrowed to embedding models, with a total count.

Note the envelope: total_count sits beside data here, and does not on GET /v1/models. That is OpenRouter's shape for the narrowed listings and ours matches it per route, so a client written against theirs parses this without a branch. Anonymous and cached.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/embeddings/models \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": [
    {
      "id": "openai/text-embedding-3-small",
      "name": "Text Embedding 3 Small",
      "category": "embedding",
      "status": "available",
      "unit": "per 1M tokens",
      "price": 0.02,
      "reference_price": 0.02,
      "pricing": { "prompt": "0.00000002", "completion": null, "request": null, "image": null },
      "supported_parameters": ["dimensions", "encoding_format"]
    }
  ],
  "total_count": 6
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.

GET/v1/images/modelsAvailable

The catalogue narrowed to image models.

Note the envelope: total_count sits beside data here, and does not on GET /v1/models. That is OpenRouter's shape for the narrowed listings and ours matches it per route, so a client written against theirs parses this without a branch. Anonymous and cached.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/images/models \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": [
    {
      "id": "google/nano-banana-2",
      "name": "Nano Banana 2",
      "category": "image",
      "status": "available",
      "unit": "per image, 1024x1024",
      "price": 0.039,
      "reference_price": 0.04,
      "pricing": { "prompt": null, "completion": null, "request": null, "image": "0.039" },
      "supported_parameters": ["size", "n", "reference_urls"]
    }
  ],
  "total_count": 24
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.

GET/v1/videos/modelsAvailable

The catalogue narrowed to video models.

Note the envelope: total_count sits beside data here, and does not on GET /v1/models. That is OpenRouter's shape for the narrowed listings and ours matches it per route, so a client written against theirs parses this without a branch. Anonymous and cached. Every model listed here is served through the queue, not through a synchronous route — see /docs/queue.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/videos/models \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": [
    {
      "id": "fal/veo3",
      "name": "Veo 3",
      "category": "video",
      "status": "available",
      "unit": "per 5s clip, 720p",
      "price": 0.75,
      "reference_price": 1.5,
      "pricing": { "prompt": null, "completion": null, "request": "0.75", "image": null },
      "supported_parameters": ["duration", "size", "prompt"]
    }
  ],
  "total_count": 18
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.

GET/v1/catalogAvailable

The discovery catalogue behind the public site: names, blurbs, families and headline rates.

camelCase, unlike every other /v1 route, because this one feeds the public site rather than an OpenAI-shaped client. Build against /v1/models instead unless you are rendering a catalogue.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/catalog \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "data": [
    {
      "id": "openai/gpt-4o-mini",
      "slug": "openai-gpt-4o-mini",
      "name": "GPT-4o mini",
      "description": "Small, fast general-purpose text model.",
      "category": "text",
      "status": "available",
      "unit": "per 1M tokens",
      "price": 0.15,
      "reference": 0.30,
      "speed": "fast",
      "featured": true,
      "capabilities": ["tools", "vision"],
      "contextLength": 128000,
      "addedAt": "2026-05-01T09:14:22Z"
    }
  ],
  "generatedAt": "2026-08-23T11:02:47Z"
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.

GET/v1/statsAvailable

Platform totals: accounts, tokens billed over the trailing 30 days, providers and live models.

Four counts and nothing derived from them. tokens is input plus output over the trailing thirty days; cached-input and reasoning tokens are excluded on purpose, so the figure matches what an account would recognise from its own usage page. Cached for five minutes.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/stats \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "accounts": 1284,
  "tokens": 91744812,
  "providers": 17,
  "models": 214,
  "generatedAt": "2026-08-23T11:02:47Z"
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.

POST/v1/mcpAvailable

JSON-RPC 2.0 over Streamable HTTP: initialise a session and call the tools.

The initialize reply carries an Mcp-Session-Id header. Send it on every later call. notifications/initialized answers 202 with no body. Tools that spend money say so in their own description.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
jsonrpcstringrequired-Always "2.0".
methodstringrequired-initialize, tools/list, tools/call, resources/list, resources/read or prompts/get.
paramsobjectoptional-Method arguments, per the MCP specification.
MCP-Protocol-Versionheaderoptional2025-06-18Negotiated protocol version. 2025-06-18, falling back to 2025-03-26.

Request

cURL
curl -X POST https://api.routehook.ai/v1/mcp \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-06-18",
      "capabilities": {},
      "clientInfo": {
        "name": "your-client",
        "version": "1.0.0"
      }
    }
  }'

Response

JSON200 OK
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "tools": { "listChanged": false },
      "resources": { "subscribe": false, "listChanged": false },
      "prompts": {}
    },
    "serverInfo": { "name": "routehook", "version": "1.0.0" }
  }
}

Errors

STATUSCODEMEANING
400invalid_requestMalformed body, or a parameter outside its bounds.
401invalid_api_keyKey missing, malformed or revoked.
402insufficient_creditsTop up the balance before retrying.
429rate_limitedBack off using the Retry-After header.
503upstream_unavailableUpstream outage. Safe to retry.
200-32601JSON-RPC error, not an HTTP one: unknown method. Transport errors stay HTTP.

GET/v1/mcpAvailable

Open the server-sent stream for server-initiated MCP messages.

text/event-stream; the object above is one event's data: payload. Only server-initiated messages arrive here. Tool calls go over POST. A session id this server does not know answers 404 carrying a JSON-RPC -32600, not the gateway's { error: { code } } envelope: an MCP client is a JSON-RPC client, and the specification makes a 404 on a request bearing a session id mean "that session is gone, call initialize again".

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
Mcp-Session-Idheaderrequired-The session id returned by initialize.

Request

cURL
curl https://api.routehook.ai/v1/mcp \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "jsonrpc": "2.0",
  "method": "notifications/message",
  "params": { "level": "info", "data": "job_ab12cd34 finished" }
}

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
429rate_limitedBack off using the Retry-After header.

DELETE/v1/mcpAvailable

End an MCP session.

There is no response body. Ending a session drops its stream; the API key itself is untouched. An unknown session id answers 404 with a JSON-RPC -32600 rather than the gateway envelope, exactly as on the stream above.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
api-key

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION
Mcp-Session-Idheaderrequired-The session to end.

Request

cURL
curl -X DELETE https://api.routehook.ai/v1/mcp \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
204 No Content

Errors

STATUSCODEMEANING
401invalid_api_keyKey missing, malformed or revoked.
429rate_limitedBack off using the Retry-After header.

GET/v1/statusAvailable

Platform health: component states, current incidents and recent uptime.

camelCase, unlike the OpenAI-shaped routes. overall and each component's status are upper case (OPERATIONAL, DEGRADED, DOWN or UNCONFIGURED), while a history day's state is lower case: operational, degraded, down or none. They are different vocabularies and a client that lower-cases one to match the other will be wrong about the day it did it to. There are four components, keyed api, providers, storage and payments, and history carries one entry per day for the whole 90-day window, oldest first (trimmed to one above). monitored is false when no probe has ever recorded a sample, which is a different claim from "everything is fine" and must not render the same way. uptime is a 0–1 fraction or null, never a percentage. The route deliberately keeps answering during maintenance (a status page that 503s while the platform is down is worse than none), and publishes measurements only: no vendor names, no topology.

AUTHENTICATION
Bearer token, Authorization header
REQUIRED SCOPE
public

Parameters

PARAMTYPEREQUIREDDEFAULTDESCRIPTION

Request

cURL
curl https://api.routehook.ai/v1/status \
  -H "Authorization: Bearer $ROUTEHOOK_API_KEY"

Response

JSON200 OK
{
  "overall": "OPERATIONAL",
  "monitored": true,
  "windowDays": 90,
  "generatedAt": "2026-08-23T11:02:47Z",
  "components": [
    {
      "key": "api",
      "name": "API",
      "description": "The gateway and the dashboards behind it.",
      "status": "OPERATIONAL",
      "uptime": 0.9997,
      "latencyMs": 84,
      "latencyMeaning": "Median round trip to the database.",
      "sampleCount": 129600,
      "checkedAt": "2026-08-23T11:02:41Z",
      "history": [
        { "date": "2026-05-26", "state": "operational", "uptime": 1, "sampleCount": 1440 }
      ]
    }
  ]
}

Errors

STATUSCODEMEANING
429rate_limitedBack off using the Retry-After header.