OpenAI-compatible API setup: your first request
One base URL, one key, three request shapes. Which endpoint a model answers on is a property of the model, not a setting you choose.
One host, three request shapes
Everything is served from https://token-share.app. What differs per model is the path and the auth header, and both are fixed by the model rather than by you: Anthropic-shaped models answer on /v1/messages with x-api-key, OpenAI-shaped models answer on /v1/responses with Authorization: Bearer, and Grok and Gemini answer on /v1/chat/completions, also with Authorization: Bearer.
The catalog names the route for every id. claude-sonnet-5 is /v1/messages, gpt-5.6-terra is /v1/responses, grok-4.6 and gemini-3-flash are /v1/chat/completions. Sending a model to the wrong shape does not silently work — the request is rejected before it leaves the proxy.
One key covers all three. There is no per-provider credential to manage, no organization header, and no separate account per vendor.
export TOKEN_SHARE_KEY="sk-..."
# Anthropic-shaped
curl https://token-share.app/v1/messages \
-H "x-api-key: $TOKEN_SHARE_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5",
"max_tokens": 256,
"messages": [{"role": "user", "content": "Say hello in one line."}]
}'
# OpenAI-shaped
curl https://token-share.app/v1/responses \
-H "Authorization: Bearer $TOKEN_SHARE_KEY" \
-H "content-type: application/json" \
-d '{
"model": "gpt-5.6-terra",
"input": "Say hello in one line."
}'
# Chat completions
curl https://token-share.app/v1/chat/completions \
-H "Authorization: Bearer $TOKEN_SHARE_KEY" \
-H "content-type: application/json" \
-d '{
"model": "grok-4.6",
"messages": [{"role": "user", "content": "Say hello in one line."}]
}'Discovering what you can call
GET /v1/models returns the catalog. It is answered by the proxy itself rather than forwarded, so the list you read is exactly the allowlist your requests are checked against — a model that appears there is callable, and one that does not will be refused.
The response shape follows your headers. Send anthropic-version and you get the Anthropic listing shape; send nothing and you get the OpenAI one. GET /v1/models/{id} returns a single entry the same way.
Model ids are ours, not the upstream vendor's marketing names. They are what the allowlist compares against, so copy them from the catalog rather than from a vendor changelog.
Confirming a request actually worked
Every response carries x-token-share-request-id. It is generated per request and exposed via CORS, so it is the handle to quote when something needs looking into. Log it next to your own request id and a support question stops being a guessing game.
You can also send x-client-request-id with your own correlation value. It is kept alongside the trace for debugging and is never used as the trace key, so replaying the same value does not collide with your earlier requests.
A rejected request is rejected early and cheaply. Auth, model allowlist and balance checks all run before anything is forwarded upstream, which is why a bad model id costs you nothing but a round trip.