Quickstart
From a funded account to a working chat completion. The API is OpenAI-compatible, so if you have used the OpenAI SDK before, the only new things here are the base URL and the trace block in the response.
Before you start
Section titled “Before you start”You need a signed-in account with a balance. If you do not have one, start at Get 0G and fund your account — a key without funds returns a payment error on the first request.
1. Create an API key
Section titled “1. Create an API key”-
In the Console, go to Dashboard → API Keys.
-
Enter a name that identifies where the key will run —
staging,agent-bot,local-dev. One key per deployment means you can revoke one without disturbing the rest. -
Optionally open Advanced settings and set a spending limit. Recommended for any key that runs unattended.
-
Click Create.
The secret appears once, starting with sk-. The Router stores only a hash and cannot show it to you again. Copy it now; if you lose it, revoke the key and create another.
Put it in your environment rather than your source tree:
export ZG_API_KEY="<YOUR_API_KEY>"2. Send your first request
Section titled “2. Send your first request”The Router speaks the OpenAI API, so the official OpenAI SDKs work unmodified — only the base URL and the key change. Install the one for your language first; the cURL tab needs nothing.
Nothing to install.
npm install openaipip install openaiExport your key so the examples can read it — never paste it into source:
export ZG_API_KEY="sk-..."Each example below reads that key from the environment, sets an explicit timeout, and surfaces errors instead of swallowing them.
curl https://router-api.0g.ai/v1/chat/completions \ --fail-with-body \ --max-time 60 \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $ZG_API_KEY" \ -d '{ "model": "glm-5", "messages": [ {"role": "user", "content": "Explain trusted execution in one sentence."} ], "max_tokens": 256 }'import OpenAI from "openai";
const apiKey = process.env.ZG_API_KEY;if (!apiKey) throw new Error("ZG_API_KEY is not set");
const client = new OpenAI({ baseURL: process.env.ZG_BASE_URL ?? "https://router-api.0g.ai/v1", apiKey, timeout: 60_000, maxRetries: 2,});
try { const res = await client.chat.completions.create({ model: "glm-5", messages: [ { role: "user", content: "Explain trusted execution in one sentence." }, ], max_tokens: 256, });
console.log(res.choices[0].message.content);
const trace = (res as Record<string, any>).x_0g_trace; console.log("request", trace.request_id, "provider", trace.provider); console.log("cost", trace.billing.total_cost);} catch (err) { if (err instanceof OpenAI.APIError) { console.error(`Router error ${err.status} ${err.code}: ${err.message}`); } throw err;}import os
from openai import OpenAI, APIError
api_key = os.environ["ZG_API_KEY"]base_url = os.environ.get("ZG_BASE_URL", "https://router-api.0g.ai/v1")
client = OpenAI( api_key=api_key, base_url=base_url, timeout=60.0, max_retries=2,)
try: res = client.chat.completions.create( model="glm-5", messages=[ {"role": "user", "content": "Explain trusted execution in one sentence."} ], max_tokens=256, )
print(res.choices[0].message.content)
trace = res.model_extra["x_0g_trace"] print("request", trace["request_id"], "provider", trace["provider"]) print("cost", trace["billing"]["total_cost"])except APIError as err: print(f"Router error {err.status_code}: {err.message}") raise3. Read the response
Section titled “3. Read the response”The response is OpenAI-shaped — choices, usage, model, id — so existing parsing code works untouched. The Router adds one block:
{ "x_0g_trace": { "request_id": "65cc8e6e-e4d6-49b9-b6b1-7e3d2596436c", "provider": "0xB01EBd79c3fd63ff52fD47C3935119601EEe2FdB", "billing": { "input_cost": "32890000000000", "output_cost": "1914160000000000", "total_cost": "1947050000000000" } }}Live response, 2026-07-20. Costs are integer strings in the smallest unit of 0G — 1018 per 0G, so this request cost 0.00194705 0G. Parse them as BigInt, never as floats; see Track what each request costs.
| Field | What it tells you |
|---|---|
request_id |
Unique identifier for this request. Log it, and quote it in any support report. |
provider |
On-chain address of the provider that actually served the request. |
billing |
Exact input, output, and total cost of this call. |
tee_verified |
Present only when verification was requested. |
Because cost arrives with the response, per-request cost attribution needs no separate billing call — log request_id alongside total_cost and you have it.
You did not choose a provider or a trust tier here, so the Router balanced across what was available. To constrain either, see trust modes and the routing headers reference.
First errors
Section titled “First errors”| Status | Code | Cause | Fix |
|---|---|---|---|
401 |
missing_authorization |
No Authorization header reached the Router |
Confirm ZG_API_KEY is exported in the process that ran the command |
401 |
invalid_api_key |
The key does not exist or was truncated when copied | Re-copy from the Console, or create a replacement |
402 |
insufficient_balance |
The deposit is spent | Top up — see Get 0G and fund your account |
None of these become valid on retry. Fix the request or the account first.
Next steps
Section titled “Next steps”- Private mode — keep prompts inside the enclave.
- Trust modes — what
standard,verified, andprivateeach guarantee. - Stream chat completions — token-by-token responses.