Skip to content
CircuitNotionAPI documentation

Developer reference

CircuitNotion API Documentation

Public reference for the CircuitNotion OpenAI-compatible AI API: base URL, authentication, chat completions, streaming, images, embeddings, completions, models, structured JSON output, function calling, Anthropic Messages compatibility, and error codes.

Base URL
https://api.circuitnotion.com/v1
Auth
Authorization: Bearer cn_…
Protocols
OpenAI & Anthropic Messages

Getting started

Introduction

What the CircuitNotion API is and which protocols it speaks.

CircuitNotion is an OpenAI-compatible AI gateway. If your code already talks to the OpenAI API, you can point it at https://api.circuitnotion.com/v1, swap in a CircuitNotion API key, and keep the rest of your integration unchanged. The gateway also speaks the Anthropic Messages protocol, so terminal agents such as Claude Code work against the same account and the same wallet.

  • OpenAI Chat Completions, Responses, Images, Embeddings and Models endpoints under https://api.circuitnotion.com/v1
  • Anthropic Messages and token counting under https://api.circuitnotion.com
  • Server-sent-event streaming on every generation endpoint
  • Function/tool calling and structured JSON output
  • Prepaid wallet billing in RWF, with per-key rate and spend limits

Getting started

Quickstart

Send your first request in under five minutes.

  • Create an account and fund your wallet at https://payment.circuitnotion.com.
  • Generate an API key in the developer platform at https://platform.circuitnotion.com. The key is shown once and starts with cn_.
  • Point any OpenAI-compatible client at https://api.circuitnotion.com/v1.
cURLbash
curl https://api.circuitnotion.com/v1/chat/completions \
  -H "Authorization: Bearer $CIRCUITNOTION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "circuit-2-turbo",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'
Pythonpython
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.circuitnotion.com/v1",
    api_key=os.environ["CIRCUITNOTION_API_KEY"],
)

response = client.chat.completions.create(
    model="circuit-2-turbo",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
JavaScriptjavascript
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://api.circuitnotion.com/v1',
  apiKey: process.env.CIRCUITNOTION_API_KEY,
});

const response = await client.chat.completions.create({
  model: 'circuit-2-turbo',
  messages: [{ role: 'user', content: 'Hello!' }],
});

console.log(response.choices[0].message.content);

Getting started

Authentication

Bearer tokens, key format, and how to keep keys safe.

Every request carries a CircuitNotion API key as a bearer token. Keys are prefixed with cn_ and are displayed exactly once at creation time, so store the value immediately in a secret manager. The Anthropic-compatible endpoints additionally accept the x-api-key header used by Anthropic clients.

Headersbash
Authorization: Bearer cn_YOUR_KEY
Content-Type: application/json

# Anthropic-style clients may instead send:
x-api-key: cn_YOUR_KEY
  • Keep keys server-side. A key in browser or mobile client code is a published key.
  • Use one key per environment or per service so a leak can be revoked in isolation.
  • Revoke an exposed key from the developer platform; revocation takes effect on the next request.
  • Each key carries an independent requests-per-minute limit and an optional daily RWF spend cap.

API reference

Chat completions

POST /v1/chat/completions — the primary text generation endpoint.

The Chat Completions endpoint accepts text and multimodal message content, developer messages, function tools, parallel tool calls, JSON response formats, the modern max_completion_tokens parameter, and the legacy max_tokens alias.

Frequently used request fields
FieldTypeDescription
modelstringA model ID from GET /v1/models, for example circuit-2-turbo.
messagesarrayConversation so far. Roles: system, developer, user, assistant, tool.
streambooleanStream the response as server-sent events. Defaults to false.
max_completion_tokensintegerUpper bound on generated tokens. max_tokens is accepted as a legacy alias.
temperaturenumberSampling temperature. Lower values are more deterministic.
toolsarrayFunction tool definitions the model may call.
response_formatobjectSet to a JSON schema or json_object to constrain output shape.
Requestbash
curl https://api.circuitnotion.com/v1/chat/completions \
  -H "Authorization: Bearer $CIRCUITNOTION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "circuit-2-turbo",
    "messages": [
      {"role": "system", "content": "You are a concise assistant."},
      {"role": "user", "content": "Summarise the CAP theorem in two sentences."}
    ],
    "max_completion_tokens": 200
  }'
Responsejson
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1758499200,
  "model": "circuit-2-turbo",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "..." },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 28,
    "completion_tokens": 64,
    "total_tokens": 92
  }
}

API reference

Streaming

Server-sent events, delta chunks, and the final usage chunk.

Set stream: true to receive the response as server-sent events. Each chunk carries an incremental delta. The stream ends with a usage chunk that reports billing totals and carries no choices, so client code must tolerate an empty choices array before the [DONE] sentinel.

Pythonpython
stream = client.chat.completions.create(
    model="circuit-2-turbo",
    messages=[{"role": "user", "content": "Explain streaming in one paragraph."}],
    stream=True,
)

for chunk in stream:
    # The final billing-usage chunk has no choices.
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
JavaScriptjavascript
const stream = await client.chat.completions.create({
  model: 'circuit-2-turbo',
  messages: [{ role: 'user', content: 'Explain streaming in one paragraph.' }],
  stream: true,
});

for await (const chunk of stream) {
  const delta = chunk.choices?.[0]?.delta?.content;
  if (delta) process.stdout.write(delta);
}

API reference

Image generation

POST /v1/images/generations — text-to-image.

Image generation follows the OpenAI Images API. Images are billed per image rather than per token, at a rate that depends on the model and the requested size.

cURLbash
curl https://api.circuitnotion.com/v1/images/generations \
  -H "Authorization: Bearer $CIRCUITNOTION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-1",
    "prompt": "A topographic map of an imaginary island, muted print colours",
    "size": "1024x1024",
    "n": 1
  }'
Pythonpython
image = client.images.generate(
    model="gpt-image-1",
    prompt="A topographic map of an imaginary island, muted print colours",
    size="1024x1024",
    n=1,
)
print(image.data[0].url or image.data[0].b64_json[:64])

API reference

Embeddings

POST /v1/embeddings — vector representations for search and RAG.

The embeddings endpoint accepts a string or an array of strings and returns float vectors. text-embedding-3-small, text-embedding-3-large, and text-embedding-ada-002 are supported, billed against the same wallet as generation requests.

Pythonpython
result = client.embeddings.create(
    model="text-embedding-3-small",
    input=["postgres connection pooling", "database connection limits"],
)

for item in result.data:
    print(item.index, len(item.embedding))
cURLbash
curl https://api.circuitnotion.com/v1/embeddings \
  -H "Authorization: Bearer $CIRCUITNOTION_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "text-embedding-3-small",
    "input": "postgres connection pooling"
  }'

API reference

Responses and completions

POST /v1/responses — the stateless Responses API adapter.

The Responses adapter accepts text and message input, function calls, function-call outputs, image input conversion, and Responses-style SSE events. It is intentionally stateless: send prior messages and tool outputs in input on every call. previous_response_id is rejected rather than silently ignored, so conversation state stays where your application can see it.

Pythonpython
response = client.responses.create(
    model="circuit-2-turbo",
    input=[{"role": "user", "content": "Give me three names for a caching library."}],
)
print(response.output_text)

API reference

Models

GET /v1/models — the live catalogue.

Query the catalogue at runtime rather than hardcoding model availability. Individual model metadata is available at GET /v1/models/{model_id}. The catalogue is the authoritative list of which IDs your key can call today.

cURLbash
curl https://api.circuitnotion.com/v1/models \
  -H "Authorization: Bearer $CIRCUITNOTION_API_KEY"
Responsejson
{
  "object": "list",
  "data": [
    { "id": "circuit-2-turbo", "object": "model", "owned_by": "circuitnotion" },
    { "id": "circuit-3", "object": "model", "owned_by": "circuitnotion" },
    { "id": "kimi-k3", "object": "model", "owned_by": "moonshot" }
  ]
}

Guides

Structured JSON output

Constrain responses to a schema your parser can trust.

Pass response_format to make the model emit JSON instead of prose. A json_schema format with strict: true is the safest option because the shape is enforced rather than merely requested.

Pythonpython
response = client.chat.completions.create(
    model="circuit-2-turbo",
    messages=[{"role": "user", "content": "Extract the invoice fields from: INV-4192, 82,500 RWF, due 2026-10-01"}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "invoice",
            "strict": True,
            "schema": {
                "type": "object",
                "properties": {
                    "number": {"type": "string"},
                    "amount_rwf": {"type": "number"},
                    "due_date": {"type": "string"},
                },
                "required": ["number", "amount_rwf", "due_date"],
                "additionalProperties": False,
            },
        },
    },
)

import json
print(json.loads(response.choices[0].message.content))

Guides

Function calling

Let the model call your own functions and read the results.

Declare tools on the request. When the model decides to call one, the response contains tool_calls instead of content. Execute the call yourself, then send the result back as a message with role tool and the matching tool_call_id. Parallel tool calls are supported.

Pythonpython
tools = [{
    "type": "function",
    "function": {
        "name": "get_wallet_balance",
        "description": "Return the current wallet balance in RWF.",
        "parameters": {
            "type": "object",
            "properties": {"account_id": {"type": "string"}},
            "required": ["account_id"],
        },
    },
}]

messages = [{"role": "user", "content": "What is the balance for account a-91?"}]

first = client.chat.completions.create(
    model="circuit-2-turbo", messages=messages, tools=tools,
)
call = first.choices[0].message.tool_calls[0]

messages.append(first.choices[0].message)
messages.append({
    "role": "tool",
    "tool_call_id": call.id,
    "content": '{"balance_rwf": 12500}',
})

final = client.chat.completions.create(
    model="circuit-2-turbo", messages=messages, tools=tools,
)
print(final.choices[0].message.content)

Guides

Coding agents and Anthropic compatibility

Claude Code, Cline, Roo Code, Hermes, and other terminal agents.

Agents that speak the OpenAI protocol — Cline, Roo Code, Hermes and similar — use the standard base URL https://api.circuitnotion.com/v1 with a cn_ key, a model ID from the catalogue, and streaming plus tool calling enabled.

Claude Code

Claude Code speaks the Anthropic Messages protocol, so it points at the root host https://api.circuitnotion.com with no /v1 suffix. POST /v1/messages and POST /v1/messages/count_tokens are both supported; token counting is free.

macOS / Linuxbash
mkdir -p ~/.claude
cat > ~/.claude/settings.json <<'EOF'
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://api.circuitnotion.com",
    "ANTHROPIC_AUTH_TOKEN": "cn_YOUR_KEY",
    "ANTHROPIC_MODEL": "kimi-k3",
    "ANTHROPIC_SMALL_FAST_MODEL": "kimi-k3"
  }
}
EOF

claude
Cline / Roo Codeyaml
provider: OpenAI Compatible
base_url: https://api.circuitnotion.com/v1
api_key: cn_YOUR_KEY
model: circuit-2-turbo
streaming: true
tool_calling: true

Operations

Billing and limits

Prepaid wallet, reservations, idempotency, and rate limits.

Billing is prepaid in RWF. Every generation request reserves its estimated maximum cost before the upstream provider is called, then settles against actual token usage once the response completes. A request that would exceed the available balance is rejected with 402 rather than partially served.

  • Send an Idempotency-Key header on retryable generation requests. Reusing an active or completed key returns 409 and never creates a second charge.
  • Reservations use a softer output cap than the max_tokens agents typically advertise, so a single agent turn does not lock the whole balance.
  • Each API key has an independent requests-per-minute limit and an optional daily RWF spending cap.
  • Balance, transactions, and top-ups live on the billing dashboard at https://payment.circuitnotion.com.

Operations

Errors

Status codes, the error envelope, and retry policy.

Errors use the OpenAI error envelope, so existing OpenAI SDK error handling works unchanged.

Error envelopejson
{
  "error": {
    "message": "Insufficient credits to complete this request.",
    "type": "invalid_request_error",
    "param": null,
    "code": null
  }
}
Status codes
StatusMeaningRetry
400Invalid requestNo — fix the request
401Missing, invalid, or revoked API keyNo
402Insufficient creditsNo — top up the wallet
404Unknown model or endpointNo
409Idempotency-Key reused while active or completedNo — read the original result
429Per-key rate limit reachedYes — exponential backoff
500Internal processing errorYes — exponential backoff
503Upstream provider unavailable or not configuredYes — exponential backoff

Operations

Production checklist

What to verify before you put the integration in front of users.

  • Store the API key in a server-side secret manager, never in client code or version control.
  • Set explicit connection and request timeouts.
  • Retry only transient errors, with exponential backoff and a bounded attempt count.
  • Handle the empty-choices streaming usage chunk.
  • Set max_completion_tokens to bound latency and cost.
  • Read GET /v1/models at runtime instead of hardcoding model availability.
  • Monitor credits and transactions on the billing dashboard.
  • Revoke keys immediately if they are exposed.