Quickstart
TokenOcean speaks the OpenAI API. If your code already calls OpenAI, you change two things:
the base_url and the API key. Nothing else.
Create an account
Email and a password. No card, no phone number. You get an API key on the spot.
Sign up freeCopy your API key
It lives on your dashboard and stays readable, so you can come back for it later.
Open dashboardSend a request
Point your client at the base URL below with the key in the Authorization header.
Base URL
Use this for every endpoint. The OpenAI SDKs want the /v1 suffix, so pass __ORIGIN__/v1 as base_url.
__ORIGIN__
__ORIGIN__/v1/chat/completions
__ORIGIN__/v1/models
Authentication
Send your key as a bearer token — this is what every OpenAI SDK does for you:
Authorization: Bearer YOUR_API_KEY
The legacy X-API-Key: YOUR_API_KEY header also works if you cannot set
Authorization. Keys are 64 characters and are case-sensitive. Never ship a key in
client-side code — call the API from your server.
Your first request
First find out which models this deployment serves (names differ between upstream providers):
curl __ORIGIN__/v1/models \ -H "Authorization: Bearer $TOKENOCEAN_API_KEY"
Pick any id from the response and use it as model below.
cURL
export TOKENOCEAN_API_KEY="YOUR_API_KEY"
curl __ORIGIN__/v1/chat/completions \
-H "Authorization: Bearer $TOKENOCEAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-flash",
"messages": [
{"role": "user", "content": "Explain vector databases in one paragraph."}
]
}'
Python (openai SDK)
pip install openai
from openai import OpenAI
client = OpenAI(
base_url="__ORIGIN__/v1",
api_key="YOUR_API_KEY",
)
resp = client.chat.completions.create(
model="deepseek-flash",
messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.choices[0].message.content)
Node.js / TypeScript (openai SDK)
npm install openai
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "__ORIGIN__/v1",
apiKey: process.env.TOKENOCEAN_API_KEY,
});
const resp = await client.chat.completions.create({
model: "deepseek-flash",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(resp.choices[0].message.content);
Streaming
Set stream: true and read server-sent events. Works the same as OpenAI:
stream = client.chat.completions.create(
model="deepseek-flash",
messages=[{"role": "user", "content": "Count to ten."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
Usage is metered as the stream ends. The final response header
X-Token-Balance-Remaining tells you the balance left afterwards.
Billing
Credits are prepaid and never expire. One credit equals one input token, and output tokens are charged at a higher rate because upstream providers charge more for them:
credits_charged = prompt_tokens × input_rate + completion_tokens × output_rate
- The rate per model is shown on your dashboard after your first call.
- Before each request we reserve
max_tokens × output_rate. If your balance cannot cover it, the request is rejected with402and nothing is sent upstream — you are never billed for a request that could not finish. - Set a smaller
max_tokensif you get402on a large balance-light account. -
Reasoning models.
deepseek-flashanddeepseek-v4-prothink before they answer: the thinking arrives in the non-standardreasoning_contentfield while the answer itself is incontent. Reasoning tokens are billed as output tokens. Ifmax_tokensis too small the model can spend the whole budget thinking and returnfinish_reason: "length"with an emptycontent— and that call is still billed. Usemax_tokens ≥ 500with these models.
Errors
Errors come back as {"error": {"message": ..., "type": ...}} with an HTTP status that matches.
| Status | Type | What to do |
|---|---|---|
400 |
invalid_request_error |
Malformed body — check that messages is an array of role/content objects, and that max_tokens is an integer. |
401 |
auth_error |
Missing or wrong key. Re-copy it from your dashboard, after the Bearer prefix. No request was sent upstream. |
402 |
insufficient_balance |
Top up a package, or lower max_tokens so the reservation fits your balance. |
502 |
upstream_error |
The model provider refused or timed out — or the model id is not served here.
The message echoes the upstream reason verbatim (e.g.
Insufficient Balance, model not found), so read it before
assuming your request was malformed. Fetch /v1/models and use the exact id.
You are not charged for these.
|
503 |
plain HTML, from the edge proxy | You exceeded the per-IP or per-key rate limit. Back off and retry with jitter; do not retry in a tight loop. |
A successful call also returns X-Token-Balance-Remaining so you can meter your own
spend without polling the dashboard.
Using other tools
Any client with an "OpenAI compatible" or "custom base URL" setting works — LangChain, LlamaIndex, Dify, n8n, LibreChat, Cline, and similar. Fill in:
- Base URL:
__ORIGIN__/v1 - API key: your TokenOcean key
- Model: an id from
/v1/models
Some editors and plugins assume OpenAI's sk- key prefix and refuse keys that do not
start with it. TokenOcean keys are 64-character opaque strings, so if a client rejects yours
for that reason, use a client that does not enforce the prefix.
FAQ
I lost my API key
Sign in and open your dashboard — the key is shown there in full, and stays valid until you ask us to rotate it.
Do I get free credits?
Yes, if this deployment has the signup bonus enabled — the exact amount is shown on the sign-up form. No card required to start.
How do I pay?
PayPal, in USD, from the dashboard. Credits are added as soon as the payment is captured.
Do credits expire?
No. Prepaid credits stay on your account until you use them.
Do you store my prompts?
We record the model name, token counts and timestamp for billing. Prompt and completion text is not stored. See the terms.
Why is my balance draining faster than token counts?
Output tokens cost more than input tokens. The dashboard breaks each call into an input and an output charge so you can see exactly where credits went.