halfoff.devDocs
Get a key
API reference

API reference

Base URLs, auth headers, response headers, rate limits and retry rules for calling Claude, GPT and Gemini through Half Off Dev's native APIs.

Half Off Dev doesn't invent a new API. It serves the three that your code and SDKs already speak, Anthropic Messages, OpenAI Chat Completions (plus Responses) and Gemini, from a single host, with one key and one prepaid balance. Bodies go in and come out in each vendor's schema, so the official SDKs need nothing more than a new base URL and key. What Half Off Dev adds is small: a few response headers, key-level limits and its own billing.

Base URLs#

Everything is served over HTTPS from https://halfoff.dev. Set the SDK's base URL to the value in the second column.

APISDK base URLEndpoints
Anthropic Messageshttps://halfoff.devPOST /v1/messages, POST /v1/messages/count_tokens
OpenAI Chat Completionshttps://halfoff.dev/v1POST /v1/chat/completions
OpenAI Responses (GPT models)https://halfoff.dev/v1POST /v1/responses
Geminihttps://halfoff.devPOST /v1beta/models/{model}:generateContent, :streamGenerateContent, :countTokens
Model list—GET /v1/models, GET /v1beta/models

Any other path, OpenAI's Embeddings API for example, answers 404.

Authentication#

A bearer token works on every endpoint. Each vendor's own header works too, so every SDK can keep its defaults.

HTTP
Authorization: Bearer ho-...
HeaderSent by
Authorization: Bearer ho-...OpenAI SDK, plain HTTP clients
x-api-key: ho-...Anthropic SDK
x-goog-api-key: ho-...Google Gen AI SDK

The model list is public. Every other endpoint needs a key. Details in Authentication.

Request and response format#

  • JSON both ways. Send bodies as JSON with content-type: application/json; responses are JSON too.
  • Streaming. Anthropic and OpenAI requests with "stream": true answer with server-sent events (text/event-stream). Gemini's :streamGenerateContent returns a streamed JSON array, or server-sent events when you add ?alt=sse, exactly as Google's API does. See Streaming.
  • CORS is open to every origin. That doesn't make browser calls a good idea: a key in front-end code is a key anyone can copy.

Response headers#

On top of the vendor's own headers, model responses include:

HeaderMeaning
x-halfoff-request-idUnique id of the call, shown in Logs. Quote it to support.
x-halfoff-groupChannel group that served the call
x-halfoff-channelShort, URL-encoded label for that channel group
x-halfoff-queued-msHow long the call waited for capacity, in milliseconds (only when it waited)
retry-afterOn 429: seconds to wait before trying again

Versioning#

Each API keeps the vendor's own versioning. Send what your SDK sends: anthropic-version and anthropic-beta for Anthropic, openai-beta for OpenAI; Gemini uses the /v1beta path like Google's API. Half Off Dev forwards those headers and no other vendor headers, so a feature that depends on some other vendor header won't be available.

Responses can gain fields over time. Write clients that skip fields they don't know.

Rate limits#

LimitApplies toWhen you go over
Requests per minute and concurrency set on a keyRequests made with that key429 with retry-after
Model capacityAll model requests. A short burst first waits a few seconds in a queue.429, usually with retry-after

More in Rate limits & failover and API keys.

Retries and idempotency#

When a channel fails, Half Off Dev tries the request on other channels before it gives up, so a 5xx that reaches you has already been retried. Still, retry 429 and 5xx on your side with exponential backoff, and respect retry-after. Other 4xx errors need a changed request, not another attempt. The official Anthropic and OpenAI SDKs retry twice by default; raise max_retries (maxRetries in Node.js) for long batch jobs.

There are no idempotency keys, which matters in one case: a request that timed out on your end may have finished and been charged anyway. Retrying it can mean paying twice. Give long generations a generous client timeout, or stream them. Listing models and counting tokens are always safe to repeat.

Ready-made retry helpers are in Errors.

Errors#

Errors come back in the format of the endpoint you called, so each SDK throws the exception it normally would. For example, an OpenAI-format request with a revoked key gets:

JSON
{"error": {"message": "Invalid or revoked API key", "type": "authentication_error", "code": "authentication_error"}}

All status codes, with sample bodies in every format, are listed in Errors.