Skip to content
Get API key

Anthropic Messages-compatible endpoint: point the Anthropic SDK's base URL at https://api.router.africa and keep your code. Set stream: true to receive Anthropic-style server-sent events.

Authenticate with x-api-key: YOUR_KEY (what the Anthropic SDK sends) or Authorization: Bearer YOUR_KEY. This is the only endpoint that accepts x-api-key.

Errors use Anthropic's error format, not the envelope of the other endpoints: {"type": "error", "error": {"type": "...", "message": "...", "reason": "..."}}. error.type is Anthropic's type; error.reason is our specific cause (see the Errors page). An error before the first token is an ordinary HTTP error. An error after streaming has started cannot change the 200; it is sent as a final event: error event and the stream ends.

Not supported: a fallbacks array and models (fallback chains are configured by router.africa, not per request).

POSThttps://api.router.africa/v1/messages

Authorizations

Use one of these.

x-api-keyapiKeyheaderrequired

Accepted on POST /v1/messages only, for Anthropic SDKs. Bearer also works there. Never put a key in the URL or the body.

Authorizationbearer (API key (sk-ra-...))headerrequired

Send your key as Authorization: Bearer YOUR_KEY. Never put a key in the URL or the body: the request is refused with key_not_in_header.

Headers

Idempotency-Keystring

router.africa extension. Works exactly as on POST /v1/chat/completions: a repeat of a finished request with the same key and the same API key returns the first result (marked x-idempotent-replay: true, not charged again); a repeat while the first is still running returns 409 request_in_progress. Without this header an identical body is treated the same way.

Max length: 255

Body application/json

modelstringrequired

A model id from GET /v1/models.

messagesobject[]required

Min items: 1

2 child fields
rolestringrequired

Allowed values: userassistant

contentstring | MessageContentBlock[]required

Text, or an array of content blocks.

1 child field
variant 1MessageContentBlock[]
3 child fields
typestringrequired
textstring
cache_controlobject
max_tokensintegerrequired

Output cap. A value above the model's ceiling is silently lowered to the ceiling; it is not an error.

Greater than 0

systemstring | MessageContentBlock[]

System prompt, as text or an array of content blocks.

1 child field
variant 1MessageContentBlock[]
3 child fields
typestringrequired
textstring
cache_controlobject
streambooleandefault: false
temperaturenumber
top_pnumber
top_kinteger
stop_sequencesstring[]
toolsobject[]
tool_choiceobject
thinkingobject

Extended thinking settings, as in Anthropic's API.

context_managementobject
metadataobject

Response

200

The message, or a stream of events when stream is true.

Response headers: x-request-id, x-idempotent-replay. Include x-request-id when you contact support.

idstringrequired
type"message"required
role"assistant"required
modelstringrequired
contentMessageContentBlock[]required
3 child fields
typestringrequired
textstring
cache_controlobject
stop_reasonstring | nullrequired
stop_sequencestring | null
usageMessageUsagerequired
4 child fields
input_tokensintegerrequired
output_tokensintegerrequired
cache_creation_input_tokensinteger | null
cache_read_input_tokensinteger | null

Streaming

Server-sent events in Anthropic's format: each event has an event: line naming its type and a data: line with one JSON MessageStreamEvent (or, last, an event: error event carrying an AnthropicError). There is no [DONE] line: the stream ends after message_stop.

Event: MessageStreamEvent
typestringrequired

Allowed values: message_startcontent_block_startcontent_block_deltacontent_block_stopmessage_deltamessage_stopping

indexinteger
messageMessage
8 child fields
idstringrequired
type"message"required
role"assistant"required
modelstringrequired
contentMessageContentBlock[]required
3 child fields
typestringrequired
textstring
cache_controlobject
stop_reasonstring | nullrequired
stop_sequencestring | null
usageMessageUsagerequired
4 child fields
input_tokensintegerrequired
output_tokensintegerrequired
cache_creation_input_tokensinteger | null
cache_read_input_tokensinteger | null
content_blockMessageContentBlock

A content block. type is for example text, image, tool_use, tool_result or thinking. cache_control may be set on a block.

3 child fields
typestringrequired
textstring
cache_controlobject
deltaobject
usageMessageUsage
4 child fields
input_tokensintegerrequired
output_tokensintegerrequired
cache_creation_input_tokensinteger | null
cache_read_input_tokensinteger | null
Event: AnthropicError
type"error"required
errorobjectrequired
4 child fields
typestringrequired

Anthropic's error type, from the HTTP status.

Allowed values: invalid_request_errorauthentication_errorbilling_errorpermission_errornot_found_errorrate_limit_errorapi_erroroverloaded_error

messagestringrequired

Safe to show to a user.

reasonstringrequired

Our specific cause, the same values as metadata.reason in the standard error.

Allowed values: invalid_bodykey_not_in_headercontext_length_exceededmissing_api_keyinvalid_api_keyinsufficient_creditskey_spend_cap_exceededaccount_suspendedcontent_policy_violationmodel_not_foundroute_not_foundupstream_timeoutrequest_in_progresspayload_too_largerate_limitedconcurrency_limitededge_rate_limitedinternal_errorprovider_errorservice_unavailableprovider_overloaded

modelstring

On model_not_found, the model id that was sent.

event: message_start
data: {"type":"message_start","message":{"id":"msg_0192f0e0","type":"message","role":"assistant","model":"anthropic/claude-sonnet-4.5","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":12,"output_tokens":1}}}

event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Habari!"}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":3}}

event: message_stop
data: {"type":"message_stop"}

(an error after streaming has started instead ends the stream with:)
event: error
data: {"type":"error","error":{"type":"overloaded_error","message":"The model provider is overloaded. Retry shortly.","reason":"provider_overloaded"}}

Errors

Errors share one body shape. Branch on error.metadata.error_type for retry logic and on error.metadata.reason for what to show your user. The full table is in Errors.

400

Same causes as the standard 400 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "Request body is invalid: `messages` is required.",
    "reason": "invalid_body"
  }
}

401

Same causes as the standard 401 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "You didn't provide an API key. Send it as `x-api-key: YOUR_KEY` or `Authorization: Bearer YOUR_KEY`.",
    "reason": "missing_api_key"
  }
}

402

Same causes as the standard 402 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "billing_error",
    "message": "This workspace doesn't have enough credits for this request. Add credits at https://app.router.africa.",
    "reason": "insufficient_credits"
  }
}

403

Same causes as the standard 403 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "permission_error",
    "message": "This account is suspended. Contact support.",
    "reason": "account_suspended"
  }
}

404

Same causes as the standard 404 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "message": "The model `anthropic/unknown` does not exist or you do not have access to it.",
    "reason": "model_not_found"
  }
}

408

Same causes as the standard 408 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "api_error",
    "message": "The model provider took too long to respond.",
    "reason": "upstream_timeout"
  }
}

409

Same causes as the standard 409 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "An identical request is already in progress.",
    "reason": "request_in_progress"
  }
}

413

Same causes as the standard 413 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "The request body is too large. Send less than 16 MiB.",
    "reason": "payload_too_large"
  }
}

429

Same causes as the standard 429 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "rate_limit_error",
    "message": "Rate limit reached for this API key. Retry after 5 seconds.",
    "reason": "rate_limited"
  }
}

500

Same causes as the standard 500 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "api_error",
    "message": "Something went wrong on our side. Reference: 0192f0e0-aaaa-7000-8000-000000000000.",
    "reason": "internal_error"
  }
}

502

Same causes as the standard 502 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "api_error",
    "message": "The model provider returned an error.",
    "reason": "provider_error"
  }
}

503

Same causes as the standard 503 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "api_error",
    "message": "The service is temporarily unavailable.",
    "reason": "service_unavailable"
  }
}

529

Same causes as the standard 529 response, in Anthropic's error format.

{
  "type": "error",
  "error": {
    "type": "overloaded_error",
    "message": "The model provider is overloaded. Retry shortly.",
    "reason": "provider_overloaded"
  }
}