Skip to main content

API Reference

The Radicalbit AI Gateway implements the OpenAI API specification — including Chat Completions, Embeddings, Audio Transcriptions, and the Responses API — making it compatible with existing OpenAI libraries and tools. It also proxies Typesafe's decision API for decision models.

Base URL​

http://localhost:9000

Authentication​

API Key Authentication​

curl -H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
http://localhost:9000/v1/chat/completions

The gateway reads the credential from the Authorization: Bearer header, which OpenAI SDKs and compatible libraries send for you. A credential past its expiry date is rejected with 401 and code key_expired_unauthorized. After a rotation, the previous value works only until the grace period ends, and is then rejected with 401 and code key_invalid_unauthorized, like a wrong value.

Endpoints​

Chat Completions​

Endpoint: POST /v1/chat/completions

Description: Creates a completion for the provided chat messages.

Request Body:

{
"model": "project-name/route-name",
"messages": [
{
"role": "user",
"content": "Hello, how are you?"
}
],
"temperature": 0.7,
"max_tokens": 100
}

Parameters:

ParameterTypeRequiredDescription
modelstringYesThe route in project-name/route-name format
messagesarrayYesArray of message objects
temperaturenumberNoSampling temperature (0.0 to 2.0)
max_tokensnumberNoMaximum tokens to generate
top_pnumberNoNucleus sampling parameter
stopstring/arrayNoStop sequences
presence_penaltynumberNoPresence penalty (-2.0 to 2.0)
frequency_penaltynumberNoFrequency penalty (-2.0 to 2.0)

Message Object:

{
"role": "user|assistant|system",
"content": "Message content"
}

Response:

{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "project-name/route-name",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! I'm doing well, thank you for asking."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 8,
"total_tokens": 18
}
}

Embeddings​

Endpoint: POST /v1/embeddings

Description: Creates an embedding for the provided input.

Request Body:

{
"model": "project-name/route-name",
"input": "The text to embed"
}

Parameters:

ParameterTypeRequiredDescription
modelstringYesThe route in project-name/route-name format
inputstring/arrayYesText to embed (string or array of strings)

Response:

{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [0.1, 0.2, 0.3, ...]
}
],
"model": "project-name/route-name",
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
}

Audio Transcriptions​

Endpoint: POST /v1/audio/transcriptions

Description: Transcribes audio into text, following the OpenAI Audio API format. Unlike the other endpoints, the request body is multipart/form-data, not JSON.

Request Body (multipart/form-data):

curl http://localhost:9000/v1/audio/transcriptions \
-H "Authorization: Bearer your-api-key" \
-F model="project-name/route-name" \
-F file="@audio.mp3" \
-F language="en"

Parameters:

ParameterTypeRequiredDescription
modelstringYesThe route in project-name/route-name format
filefileYesThe audio file to transcribe
languagestringNoLanguage of the input audio, in ISO-639-1 format (e.g. en)
promptstringNoText to guide the model's style, or to continue a previous audio segment
response_formatstringNojson (default) or verbose_json. verbose_json is only supported by whisper-1 models
temperaturenumberNoSampling temperature (0.0 to 1.0)
streambooleanNoStream the transcript as it's generated, via SSE. Only supported by the gpt-4o-transcribe family, not by whisper-1
note

The gateway supports two model families, with different capabilities:

  • whisper-1: returns a full verbose_json response with language, duration and segments, but does not support streaming.
  • gpt-4o-transcribe family (gpt-4o-transcribe, gpt-4o-mini-transcribe): supports streaming, but only returns a plain json response.

Response (response_format: "json"):

{
"text": "Hello, how are you today?"
}

Response (response_format: "verbose_json", whisper-1 only):

{
"language": "english",
"duration": 3.2,
"text": "Hello, how are you today?",
"segments": [
{
"id": 0,
"start": 0.0,
"end": 3.2,
"text": "Hello, how are you today?"
}
]
}

Streaming Response:

When stream is true, the gateway returns a Server-Sent Events (SSE) stream of transcript deltas, ending with a [DONE] marker:

data: {"type":"transcript.text.delta","delta":"Hello,"}

data: {"type":"transcript.text.delta","delta":" how are you today?"}

data: {"type":"transcript.text.done","text":"Hello, how are you today?"}

data: [DONE]
warning

stream: true is not supported by whisper-1 and returns an error.

Responses API​

Endpoint: POST /v1/responses

Description: Creates a response using the OpenAI Responses API format (stateless Phase 1). The gateway translates the request to Chat Completions internally, so all gateway features (guardrails, caching, rate limiting) apply as usual.

tip

The model field works exactly like in Chat Completions — it maps to a route name from your config.yaml, not directly to an upstream model name.

warning

The gateway operates in stateless mode only. Setting previous_response_id will return an error. Multi-turn conversations must be managed client-side.

Request Body:

{
"model": "project-name/route-name",
"input": "What is the capital of France?",
"instructions": "You are a helpful assistant.",
"stream": false,
"temperature": 0.7,
"max_output_tokens": 200
}

The input field also accepts a list of message objects:

{
"model": "project-name/route-name",
"input": [
{"role": "user", "content": "What is the capital of France?"}
]
}

Parameters:

ParameterTypeRequiredDescription
modelstringYesThe route in project-name/route-name format
inputstring or arrayYesUser prompt or list of message objects
instructionsstringNoSystem-level instructions (equivalent to a system message)
streambooleanNoWhether to stream the response
temperaturenumberNoSampling temperature
top_pnumberNoNucleus sampling parameter
max_output_tokensintegerNoMaximum output tokens (mapped to max_completion_tokens)
toolsarrayNoFunction tools to make available
tool_choicestring or objectNoTool selection strategy
parallel_tool_callsbooleanNoAllow parallel tool calls
userstringNoEnd-user identifier forwarded to the upstream provider
previous_response_idstringNoNot supported — raises an error

Response:

{
"id": "resp_123",
"object": "response",
"created_at": 1677652288,
"model": "project-name/route-name",
"output": [
{
"type": "message",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "The capital of France is Paris."
}
]
}
],
"usage": {
"input_tokens": 10,
"output_tokens": 8,
"total_tokens": 18
}
}

Decision Models​

Endpoint: POST /v1/systemone

Description: Asks a decision model (Typesafe's Jev) structured questions about a piece of input, and returns a typed answer with a confidence for each question. The endpoint mirrors Typesafe's API: the body uses Typesafe's format, except that model is your gateway route. The gateway forwards the request and returns Typesafe's status and body unchanged.

tip

Any Typesafe client works through the gateway. Point its base URL at the gateway, use a gateway API key, and set model to project-name/route-name.

warning

Streaming is not supported. The response is always returned in one piece.

Request Body:

{
"model": "project-name/route-name",
"state": "My card was charged twice and I need the money back today!",
"questions": {
"intent": {
"type": "choice",
"instructions": "What does the customer want?",
"criteria": {
"refund": "Wants money back",
"information": "Wants an explanation",
"complaint": "Wants to complain"
}
},
"is_urgent": {
"type": "noul",
"instructions": "Does this convey urgency?"
},
"frustration": {
"type": "score",
"instructions": "How frustrated is the customer?",
"criteria": ["Calm", "Mildly annoyed", "Clearly frustrated", "Angry"]
}
}
}

Parameters:

ParameterTypeRequiredDescription
modelstringYesThe route in project-name/route-name format. The gateway replaces it with the configured Typesafe model
statestring/object/arrayYesThe input to evaluate. Route input guardrails check and redact its text values
questionsobjectYesMap of question id to question object
other fieldsanyNoForwarded to Typesafe unchanged

Question Object:

FieldTypeRequiredDescription
typestringYeschoice, score or noul
instructionsstringYesThe question to answer
criteriaobject/arrayDepends on typechoice: map of option to description. score: ordered list of levels. noul: optional description of what yes and no mean

Question Types:

TypeAnswersMain answer field
choiceOne option out of a setchoice, with probabilities and confidence
scoreA position on an ordered scalescore, with probabilities and confidence
noulA yes/no statementnoul, the probability (0 to 1) that the statement is true

See Typesafe's documentation for the full question and answer format.

Response:

{
"model": "jev-1.13.0",
"answers": {
"intent": {
"type": "choice",
"choice": "refund",
"confidence": 1.0,
"probabilities": { "refund": 1.0, "information": 0.0, "complaint": 0.0 }
}
},
"usage": {
"input_tokens": 337,
"output_tokens": 31
}
}

The response is Typesafe's body, unchanged. model holds the Typesafe model that answered, not your route. Cost is computed on usage.input_tokens only. See Limits and Cost.

Errors:

StatusCause
400Unknown route, a route with no decision models, or a guardrail block or soft block (guardrail_violation_bad_request)
401Missing, invalid or expired gateway key, or a key that does not belong to the route
422The request body is invalid, for example model is missing
429A rate, token or budget limit is full
502No decision model answered (model_invoker_bad_gateway)
Other 4xxReturned by Typesafe and forwarded unchanged. They are not retried and do not trigger fallback

Error Responses​

Standard Error Format​

Errors follow the OpenAI error format, so OpenAI SDKs raise them as regular API errors:

{
"error": {
"message": "The route name [my-project/my-route] was not found in the config",
"type": "gateway_error",
"param": null,
"code": "gateway_bad_request"
}
}
  • type is the error family, for example authentication_error, rate_limit_error or guardrail_error.
  • code is the specific error. Use it to tell errors apart.

Common Error Codes​

StatusCodeDescriptionSolution
400gateway_bad_requestUnknown route, or a route with no models of the requested kindCheck the model field (project-name/route-name) and the route configuration
400guardrail_violation_bad_requestContent blocked by a guardrailReview the guardrail configuration
401key_missing_unauthorizedNo credential in the requestSend the credential in the Authorization: Bearer header
401key_invalid_unauthorizedUnknown credential, a credential whose group is not linked to the route, or a previous value used after its grace periodCheck the credential value and its group's routes
401key_expired_unauthorized"API key has expired.": the credential's expiry date has passedAsk an Admin for a new credential
401invalid_jwt_tokenInvalid identity provider token (Enterprise, see Access Control)Get a new token from the identity provider
429request_rate_limitedRate limit exceededRetry later, or raise the limit
429token_limit_rate_limitedToken limit exceededRetry later, or raise the limit
429budget_limit_rate_limitedBudget limit exceededRaise the budget, or wait for the next budget window
502model_invoker_bad_gatewayNo decision model answered, fallbacks includedCheck Typesafe's status and the fallback configuration