Quickstart
This guide takes you from no key to a streamed answer. You start with a sandbox key, so nothing is billed while you wire things up, then switch to a live key by changing one environment variable.
-
Create a sandbox key
Section titled “Create a sandbox key”Keys are created by an owner or administrator of your organization, in the organization dashboard under Governance → API keys. Select New key, give it a name, and set Mode to Sandbox. The token starts with
bel_test_.The token is shown once. Copy it and store it as an environment variable:
Terminal window export BELAREL_API_KEY="bel_test_..." -
Make your first call
Section titled “Make your first call”First, list the models your key may call. Pick an
idfrom the answer:Terminal window curl https://api.belarel.com/v1/models \-H "Authorization: Bearer $BELAREL_API_KEY"Then send a chat completion. The examples use
openai/gpt-5.4-mini; replace it with anidfrom your own list.Terminal window curl https://api.belarel.com/v1/chat/completions \-H "Authorization: Bearer $BELAREL_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "openai/gpt-5.4-mini","messages": [{ "role": "user", "content": "Say hello in one word." }],"max_tokens": 64}'import osfrom openai import OpenAIclient = OpenAI(base_url="https://api.belarel.com/v1",api_key=os.environ["BELAREL_API_KEY"],)completion = client.chat.completions.create(model="openai/gpt-5.4-mini",messages=[{"role": "user", "content": "Say hello in one word."}],max_tokens=64,)print(completion.choices[0].message.content)print(completion._request_id) # from the X-Request-Id headerprint(completion.model_extra.get("belarel")) # the Belarel blockimport OpenAI from 'openai';const client = new OpenAI({baseURL: 'https://api.belarel.com/v1',apiKey: process.env.BELAREL_API_KEY,});const completion = await client.chat.completions.create({model: 'openai/gpt-5.4-mini',messages: [{ role: 'user', content: 'Say hello in one word.' }],max_tokens: 64,});console.log(completion.choices[0].message.content);console.log(completion._request_id); // from the X-Request-Id headerconsole.log((completion as unknown as { belarel: unknown }).belarel); -
Read the answer
Section titled “Read the answer”A sandbox key never reaches a real model: the answer echoes your last message after a
[sandbox]marker, and the cost is zero. Everything else has the shape a live answer has:{"id": "chatcmpl-3b2f9c1e-7a4d-4f0e-9a51-0c6d2e8b4f17","object": "chat.completion","created": 1759400000,"model": "openai/gpt-5.4-mini","choices": [{"index": 0,"message": { "role": "assistant", "content": "[sandbox] Say hello in one word." },"finish_reason": "stop"}],"usage": {"prompt_tokens": 20,"completion_tokens": 8,"total_tokens": 28,"prompt_tokens_details": { "cached_tokens": 0 },"completion_tokens_details": { "reasoning_tokens": 0 }},"belarel": {"request_id": "req_8c0e4b7a2f9d41c6b3e05a7d9f2c1e84","model_requested": "openai/gpt-5.4-mini","model_served": "openai/gpt-5.4-mini","cost": { "usd": 0, "credits": 0, "source": "estimated", "billing": "sandbox" },"policy": {"decisions": [{ "rule": "org_api_catalog", "verdict": "allow", "detail": "residency any" }]},"data_mode": "standard"}}What to look at:
usage— tokens in the OpenAI shape, with cached and reasoning tokens broken out.belarel.request_id— the same value as theX-Request-Idresponse header. Log it: it is what you look up with GET/v1/requests/{id}and what support asks for.choices[0].finish_reason— why the model stopped:stop,lengthwhenmax_tokenscut the reply short,content_filter, ortool_calls.belarel.model_served— the model that actually ran the call.belarel.cost—usdat your organization’s price,credits, where the figure comes from (source), and how it is billed (billing:platform,byokorsandbox).belarel.policy.decisions— the rules that let the call through.belarel.data_mode— how the content of the call was handled.belarel.ignored_parameters— present only when the model’s provider ignored a parameter you sent, such asseed.
-
Stream it
Section titled “Stream it”Set
stream: trueto receive server-sent events. The stream ends with one extra chunk that has an emptychoicesarray and carriesusageandbelarel, thendata: [DONE]. You get it on every stream, without asking for it.Terminal window curl -N https://api.belarel.com/v1/chat/completions \-H "Authorization: Bearer $BELAREL_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "openai/gpt-5.4-mini","messages": [{ "role": "user", "content": "Count to three." }],"stream": true}'stream = client.chat.completions.create(model="openai/gpt-5.4-mini",messages=[{"role": "user", "content": "Count to three."}],stream=True,)for chunk in stream:if chunk.choices:print(chunk.choices[0].delta.content or "", end="", flush=True)else:# The closing chunk: usage and the Belarel block.print("\n", chunk.usage, chunk.model_extra.get("belarel"))const stream = await client.chat.completions.create({model: 'openai/gpt-5.4-mini',messages: [{ role: 'user', content: 'Count to three.' }],stream: true,});for await (const chunk of stream) {if (chunk.choices.length > 0) {process.stdout.write(chunk.choices[0].delta.content ?? '');} else {// The closing chunk: usage and the Belarel block.console.log('\n', chunk.usage, (chunk as unknown as { belarel: unknown }).belarel);}} -
Switch to a live key
Section titled “Switch to a live key”When your integration works in the sandbox, create a second key with Mode set to Live (prefix
bel_live_) and swap the environment variable. Your code does not change.Terminal window export BELAREL_API_KEY="bel_live_..."What changes with a live key:
- The call reaches the real model and is billed from your organization’s credits.
- The key’s spend caps and your organization’s budgets and contract ceilings apply.
belarel.costcarries the real figure. If it is not known when the answer is sent,cost.sourceispending, and GET/v1/requests/{id}gives the settled figure later.

