Usage Events API
Ingest a usage event
Records an AI usage event for cost calculation. Call it with a POST request to /usage-events, authenticated with a restricted API key and the "usage:write" scope.
POST https://api.bearlumen.com/v1/usage-events
Records an AI usage event for cost calculation. Events are processed asynchronously; this endpoint returns immediately with 202 Accepted. Accepted events are queued for cost calculation and appear in the cost and attribution analytics endpoints once processing completes, typically shortly after ingestion. This endpoint requires HMAC request signing (X-Signature and X-Timestamp headers) in addition to your API key, and retries are safe because events are deduplicated by their idempotency_key. See the Request signing (HMAC) and Idempotency sections of this reference for the full details. Attribution works in three layers: your organization is identified implicitly by the API key, so there is no customer_id field to send. Your own end users are attributed with the optional user_id field, and any other attribute you care about (team, tenant, environment) goes in metadata. After a 202, confirm the event landed with GET /usage/events; cost figures appear in the cost-data endpoints once processing completes. **Flagged events:** status "accepted_flagged" means the event was accepted and will be processed, but needs attention. Causes: timestamp more than 24 hours old, timestamp more than 1 minute in the future, plan event quota soft limit reached, or (when no cost_override is supplied) no rate card configured for the model, in which case cost cannot be calculated until a rate card exists. flag_reason states the specific cause. When your plan quota passes its soft limit, 202 responses include an X-BearLumen-Usage-Warning header. Requests count toward your per-API-key rate limit; sustained overruns return 429 with the standard error envelope.
Authentication and scopes
Authenticate with a restricted API key in the Authorization: Bearer <key> header. This endpoint requires the usage:write scope. It also requires HMAC request signing (the X-Signature and X-Timestamp headers) in addition to your API key.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
x-signature | header | string | No | HMAC signature of this request in the form v1={hex}; see HMAC signing above. Requests without a valid signature are rejected with 401. |
x-timestamp | header | string | No | Unix timestamp (in seconds) used in the signed payload; timestamps more than 5 minutes from server time are rejected with 401. |
Request example
{
"idempotency_key": "3f9a2b1c-8d7e-4f6a-9b2c-1a2b3c4d5e6f",
"model": "gpt-4o",
"input_tokens": 1500,
"output_tokens": 420,
"event_invoked_at": "2026-01-15T10:30:00.000Z",
"user_id": "user_123",
"provider": "openai",
"feature": "chat"
}
Response example
Success response (202):
{
"event_id": "166a63b3-5388-5423-8f3f-d6508823557f",
"message": "Event accepted for processing",
"status": "accepted"
}
Error codes
Errors return the standard error envelope with a code, message, and a correlationId you can quote to support.
| Status | When it happens |
|---|---|
400 | Invalid request data. error.message names the failing field and the constraint to satisfy before retrying. |
401 | Authentication failed. Check your Authorization: Bearer API key and the X-Signature and X-Timestamp headers. API key failures return the standard error envelope; HMAC signature verification failures return a flat { "error": string, "code": string } body instead. |
403 | Insufficient permissions. Use an API key that has the usage:write scope. |
429 | Plan event quota exceeded. Includes X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After (seconds until the next period) headers; back off until Retry-After elapses or upgrade your plan. |
Rate limits and retries
Plan event quota exceeded. Includes X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After (seconds until the next period) headers; back off until Retry-After elapses or upgrade your plan.
Retries are safe: events are deduplicated by their idempotency_key, so resending an event that already landed will not double-count it.