Quickstart

One key and one base URL. Any OpenAI or Anthropic client can then talk to the models zdr.sh serves.

Base URL and key#

SettingValue
Base URL (OpenAI format)https://api.zdr.sh/v1
Base URL (Anthropic format)https://api.zdr.sh
API keya duck- key from the dashboard
Modelsglm-5.3, glm-5.3-flash, deepseek-v4.1-flash, deepseek-dgx and the other ids on Models

The dashboard is at zdr.sh/app. The API is a different host, api.zdr.sh. The Anthropic base URL is the origin only, because the Anthropic SDKs append /v1/messages themselves.

Create an account and a key#

  1. Sign up at zdr.sh/signup and confirm your email.
  2. Open the dashboard and choose Create key.
  3. Copy the secret. It starts with duck- and is shown once; afterwards the dashboard keeps only its prefix.

Store the key in the environment, never in code:

bash
export ZDR_API_KEY=duck-...

Every request carries it as Authorization: Bearer $ZDR_API_KEY or as x-api-key. When both are present, the first duck- credential wins.

Add credit#

A new account has no balance, so a request is refused with 402 insufficient_balance before it reaches a model. Choose Top up in the dashboard, pay the amount in crypto to the address the screen shows, and the balance moves when the transfer reaches the confirmations that asset requires. There is no subscription and no renewal: the balance is the only limit.

Zero retention explains what is kept, and Errors lists the refusal codes.

Send your first request#

bash
curl -sSf https://api.zdr.sh/v1/chat/completions \  -H "Authorization: Bearer $ZDR_API_KEY" \  -H "Content-Type: application/json" \  -d '{"model": "glm-5.3", "messages": [{"role": "user", "content": "Say hello in one short sentence."}]}'

The answer is an OpenAI chat.completion: choices[0].message.content, a usage object and the response headers.

Stream the answer#

Set stream to true and the answer arrives as server-sent events, one JSON chunk per line, closed by data: [DONE].

cURLbash
curl -sSfN https://api.zdr.sh/v1/chat/completions \  -H "Authorization: Bearer $ZDR_API_KEY" \  -H "Content-Type: application/json" \  -d '{"model": "glm-5.3", "stream": true, "messages": [{"role": "user", "content": "Count to three."}]}'

The Anthropic format#

The same conversation through the Messages endpoint. The base URL is the origin and the request carries anthropic-version:

cURLbash
curl -sSf https://api.zdr.sh/v1/messages \  -H "x-api-key: $ZDR_API_KEY" \  -H "anthropic-version: 2023-06-01" \  -H "Content-Type: application/json" \  -d '{"model": "glm-5.3", "max_tokens": 128, "messages": [{"role": "user", "content": "Say hello in one short sentence."}]}'

The endpoints#

MethodPathPurpose
POST/v1/chat/completionsOpenAI Chat Completions
POST/v1/messagesAnthropic Messages
POST/v1/responsesOpenAI Responses, stateless
POST/v1/embeddingsOpenAI Embeddings
POST/v1/messages/count_tokensInput token count of a Messages payload
POST/v1/responses/input_tokensInput token count of a Responses payload
GET/v1/modelsThe models the key may use
GET/v1/usageBalance and spend of the day
POST/v1/tools/searchWeb search, one to four queries
GET/v1/tools/searchWhether search is available
POST/v1/tools/browseA public page's readable text, free
POST/mcpThe memory vault over MCP, for a key with MCP on

The audio, image and rerank endpoints are not served: they answer 404 endpoint_not_supported. The API host also answers GET /api/hello as a warm-up probe, and the dashboard host serves its own /api/* routes.

Headers on the answer#

HeaderMeaning
x-request-idThe request id, quote it in a support message
x-token-costWhat the request cost, in EUR (a trailer on a stream)
x-ratelimit-*The key's limits, what is left and when it resets
x-token-cachehit when the response cache answered
x-token-noticeWhat the service changed or left out
x-ai-generated, x-ai-modelThe answer is AI-generated, and the model that wrote it
retry-afterOn a 429 or a 503, the seconds to wait

Next#