API Reference
Direct REST API for event ingestion and custom integrations.
The noburn REST API accepts events from any language or runtime. Use it if your language doesn't have an SDK yet, or if you want full control over the request.
Authentication
All API requests use Bearer token authentication with your project's SDK key:
Authorization: Bearer sk-nb-xxxxxxxxxxxxxxxxSDK keys are project-scoped. A key can only write events to its associated project.
POST /api/v1/events
Records an LLM event (blocked or allowed). This is the core ingestion endpoint — the SDK wraps this call.
Runtime: Edge (Vercel Edge Functions) Target latency: p99 < 150ms
The server returns 202 immediately and processes the event asynchronously. Budget evaluation, alert rule checks, and webhook dispatches happen after the response.
Request
POST https://noburn.dev/api/v1/events
Authorization: Bearer sk-nb-xxxxxxxxxxxxxxxx
Content-Type: application/json{
"project_id": "550e8400-e29b-41d4-a716-446655440000",
"model": "gpt-4o",
"tokens_in": 1423,
"tokens_out": 487,
"cost_usd": 0.00848,
"was_blocked": false,
"end_user_id": "user_abc123",
"block_reason": null,
"latency_ms": 1240,
"timestamp": "2025-01-15T14:32:00.000Z"
}Request body
| Field | Type | Required | Description |
|---|---|---|---|
project_id | string (uuid) | ✓ | Must match the project associated with your SDK key |
model | string | ✓ | Model identifier. Max 255 characters |
tokens_in | number | ✓ | Prompt token count |
tokens_out | number | ✓ | Completion token count |
cost_usd | number | ✓ | Cost in USD. Use your provider's per-token pricing |
was_blocked | boolean | ✓ | true if the call was blocked before reaching the LLM |
end_user_id | string | — | Per-user identifier for spend tracking. Max 255 characters |
block_reason | string | — | Why the call was blocked. Max 500 characters |
latency_ms | number | — | End-to-end call latency in milliseconds |
timestamp | string (ISO 8601) | — | Defaults to server time if omitted |
Response
HTTP/1.1 202 AcceptedNo response body. A 202 means the event was accepted and queued for processing.
Error responses
| Status | Code | Reason |
|---|---|---|
400 | BAD_REQUEST | Missing required fields or invalid types |
401 | INVALID_KEY | Missing or malformed Authorization header |
403 | INVALID_KEY | SDK key is valid but project_id doesn't match |
429 | RATE_LIMIT | Exceeded 1,000 requests/minute per IP |
Rate limits
| Tier | Limit |
|---|---|
| All plans | 1,000 requests/min per IP |
Set Retry-After header is included on 429 responses.
Example — raw fetch (Node.js)
await fetch('https://noburn.dev/api/v1/events', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.NOBURN_SDK_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
project_id: process.env.NOBURN_PROJECT_ID,
model: 'gpt-4o',
tokens_in: 1423,
tokens_out: 487,
cost_usd: 0.00848,
was_blocked: false,
latency_ms: 1240,
}),
});Example — curl
curl -X POST https://noburn.dev/api/v1/events \
-H "Authorization: Bearer sk-nb-xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"project_id": "550e8400-e29b-41d4-a716-446655440000",
"model": "claude-3-5-sonnet-20241022",
"tokens_in": 800,
"tokens_out": 200,
"cost_usd": 0.00284,
"was_blocked": true,
"block_reason": "budget_exceeded"
}'Cost calculation reference
noburn stores whatever cost_usd you send. Use your LLM provider's pricing:
| Model | Input (per 1M tokens) | Output (per 1M tokens) |
|---|---|---|
gpt-4o | $2.50 | $10.00 |
gpt-4o-mini | $0.15 | $0.60 |
claude-3-5-sonnet-20241022 | $3.00 | $15.00 |
claude-3-haiku-20240307 | $0.25 | $1.25 |
gemini-1.5-pro | $1.25 | $5.00 |
def calculate_cost(model: str, tokens_in: int, tokens_out: int) -> float:
pricing = {
"gpt-4o": (2.50 / 1e6, 10.00 / 1e6),
"gpt-4o-mini": (0.15 / 1e6, 0.60 / 1e6),
"claude-3-5-sonnet-20241022": (3.00 / 1e6, 15.00 / 1e6),
}
input_price, output_price = pricing.get(model, (0.001 / 1e6, 0.002 / 1e6))
return tokens_in * input_price + tokens_out * output_priceGET /api/v1/policy
Fetches the enabled policy rules for a project. baar-core calls this on BAARRouter initialization to load server-configured rules.
Runtime: Edge (Vercel Edge Functions)
Query parameters
| Parameter | Required | Description |
|---|---|---|
project_id | ✓ | Your project UUID |
Request
GET /api/v1/policy?project_id=<your-project-id>
Authorization: Bearer sk-nb-xxxxxxxxxxxxxxxxResponse
{
"rules": [
{ "when": { "utilization": ">= 0.8" }, "then": "force_small" },
{ "when": { "model": "gpt-4o" }, "then": "block" }
]
}Rules are returned in evaluation order (position ascending). Only enabled rules are included. An empty rules array means no rules are configured — all calls proceed normally.
Error responses
| Status | Meaning |
|---|---|
401 | Missing or invalid SDK key |
403 | SDK key does not belong to the requested project_id |
400 | project_id query param missing |
Error codes
| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED | 401 | Not signed in |
FORBIDDEN | 403 | Signed in but access denied |
INVALID_KEY | 401/403 | SDK key missing, invalid, or project mismatch |
NOT_FOUND | 404 | Resource doesn't exist |
BAD_REQUEST | 400 | Invalid request body |
RATE_LIMIT | 429 | Too many requests |
PLAN_LIMIT_EXCEEDED | 402 | Action requires plan upgrade |
INTERNAL_ERROR | 500 | Server error — retry with backoff |