Anthropic SDK
The official Anthropic SDK (Python or TypeScript) speaks the Anthropic Messages protocol, which MirAPI implements on the bare API origin. To switch from Anthropic to MirAPI, change only the base URL and API key; request and response shapes stay the same.
What you need
Section titled “What you need”| Element | Value |
|---|---|
| Base URL | https://api.mirapi.ai (bare origin, no /v1) |
| API key | MIRAPI_API_KEY |
| Model | deepseek-chat |
The SDK authenticates with the x-api-key header by default. MirAPI accepts both x-api-key and Authorization: Bearer on /v1/messages.
Install
Section titled “Install”pip install anthropicnpm install @anthropic-ai/sdkConfigure
Section titled “Configure”Python
Section titled “Python”import osfrom anthropic import Anthropic
client = Anthropic( base_url="https://api.mirapi.ai", api_key=os.environ["MIRAPI_API_KEY"],)TypeScript
Section titled “TypeScript”import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({ baseURL: "https://api.mirapi.ai", apiKey: process.env.MIRAPI_API_KEY,});The SDK sends the anthropic-version header by default; MirAPI accepts it like any other header.
Verify with a message
Section titled “Verify with a message”message = client.messages.create( model="deepseek-chat", max_tokens=200, messages=[{"role": "user", "content": "Reply with exactly: connected to MirAPI"}],)print(message.content[0].text)The output should contain connected to MirAPI. The Anthropic protocol requires max_tokens, so set it on every call.
Streaming
Section titled “Streaming”with client.messages.stream( model="deepseek-chat", max_tokens=200, messages=[{"role": "user", "content": "Count from 1 to 5."}],) as stream: for text in stream.text_stream: print(text, end="")Streaming uses standard SSE. Reasoning content, when the model produces it, arrives before the final answer.
Prompt caching
Section titled “Prompt caching”Add cache_control to a system or messages block to mark a cache breakpoint:
message = client.messages.create( model="deepseek-chat", max_tokens=200, system=[ { "type": "text", "text": "You are a helpful assistant.", "cache_control": {"type": "ephemeral"}, } ], messages=[{"role": "user", "content": "Hello"}],)- You can mark up to 4 breakpoints.
"ttl": "1h"extends the cache to 1 hour and raises the write price. - The model’s vendor sets the minimum cacheable length and the TTL (Claude 1,024–4,096 tokens; OpenAI 1,024; default about 5 minutes).
- To confirm a hit, check the
usage.prompt_tokens_details.cached_tokensandcache_write_tokensfields. Cache reads are cheaper than normal input.
Errors and troubleshooting
Section titled “Errors and troubleshooting”| Status | Meaning | What to do |
|---|---|---|
| 401 | Missing, invalid, or unknown key | Fix your credentials |
| 403 | Valid key, but rejected | Resolve the cause and retry (balance, whitelist, quota, IP allowlist) |
| 413 | Payload too large | Reduce the request size |
| 429 | Rate limited | Retry with jittered exponential backoff (1s → 2s → 4s, cap ~30s) |
| 500 | Gateway or upstream error | Idempotent requests are safe to retry |
The Anthropic error envelope looks like this:
{"type":"error","error":{"type":"permission_error","message":"..."}}Every error message ends with a request ID; include it when you open a support ticket. A 403 with a valid key usually means the model is not on your whitelist or the balance is exhausted.
Billing
Section titled “Billing”- A non-streaming response’s
usagereports token counts only, never the amount charged. Check the amount in the Platform or withGET /api/log/token. - Text and multimodal chat are billed per token (input, output, and cache read, in USD per 1M tokens). Reasoning tokens are billed as output.
- Your balance is prepaid in USD and never expires, and there is no subscription or monthly fee. When it runs out, calls fail with 403; after you top up, the same key works again immediately.
Troubleshooting
Section titled “Troubleshooting”- Bare
base_url, no/v1. The SDK builds/v1/messagesitself; adding/v1duplicates the segment. /v1/messages/count_tokensis not implemented and returns 404. The SDK exposes it, but you do not need to count tokens to callmessages.create.- Unsupported parameters. Tool use, streaming, and
thinkingwork only when the upstream model supports them; the upstream may ignore or reject parameters it does not support. - 429 has no
Retry-Afterheader. Implement backoff in your client instead of waiting for a hint. baseURLvsbase_url. The Python SDK usesbase_url; the TypeScript SDK usesbaseURL.