Features / Observability
Every request of a chat, on one timeline.
Tag requests with a session id and see a whole roleplay or agent run as one timeline: models, tokens, cost and latency per step. Export it as CSV or stream it to the tracing tool you already use.
What you can read
- Sessions
- GET /v1/sessionsrequests, models, tokens, cost, errors per session
- One session
- GET /v1/sessions/{id}up to 1,000 steps in order
- Usage CSV
- GET /v1/usage/exportup to 92 days and 200,000 rows a file
- One request
- GET /v1/requests/{id}tokens and charge, plus its signed receipt
Limits you can set per key
- Session caps
- requests an hour, dollars429 session_cap when reached
- Loop guard
- on or off429 loop_detected on the sixth repeat in 10 minutes
- Concurrency
- requests in flight
- Spend limit
- daily, weekly or monthlyresets at 00:00 UTC, Monday or the 1st
- Budget
- dollars carved from the balance
Tag a session
curl https://api.uncensoredllm.ai/v1/chat/completions \ -H "Authorization: Bearer sk-ullm-live-…" \ -H "Content-Type: application/json" \ -H "x-session-id: user-42:chat-7" \ -d '{"model": "glm-5.3-uncensored", "messages": [{"role": "user", "content": "Hello"}]}'Read sessions and export usage
Reading sessions and the CSV takes an admin key, created in the console; it manages keys and exports and cannot call models.
# Sessions, newest activity firstcurl https://api.uncensoredllm.ai/v1/sessions -H "Authorization: Bearer $ULLM_ADMIN_KEY" # Every request of one session, with tokens, cost, latency and outcomecurl https://api.uncensoredllm.ai/v1/sessions/user-42:chat-7 -H "Authorization: Bearer $ULLM_ADMIN_KEY" # The month as CSVcurl "https://api.uncensoredllm.ai/v1/usage/export?from=2026-10-01&to=2026-10-31" \ -H "Authorization: Bearer $ULLM_ADMIN_KEY" -o usage.csvStream traces to your backend
Add a destination once and every finished request is sent there: webhook, langfuse or otlp. Secrets are stored encrypted and never shown again.
curl https://api.uncensoredllm.ai/v1/exports \ -H "Authorization: Bearer $ULLM_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "kind": "otlp", "name": "traces", "endpoint": "https://otlp.example.com", "headers": {"x-api-key": "YOUR_BACKEND_KEY"} }'Cap a session before it runs away
curl -X PATCH https://api.uncensoredllm.ai/v1/keys/KEY_ID \ -H "Authorization: Bearer $ULLM_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{ "session_max_requests": 200, "session_max_spend_usd": 2, "loop_guard": true, "concurrency": 8, "monthly_cap_usd": 50, "spend_limit_period": "weekly" }'Each request still carries its own signed receipt, checkable at /statements/verify. The console’s key dialog sets the same limits; every field is in the console docs.
Questions
Send the same x-session-id header (1 to 128 visible characters) on every request of a chat or an agent run. Without the header, x-uplink-session or a session_id or user field in the body does the same. Hosted agents group their turns on their own.
In the console under Usage → Sessions, as a timeline of every request with its model, tokens, cost, latency and outcome, or through GET /v1/sessions and /v1/sessions/{id} with an admin key.
A webhook of your own (JSON batches signed with HMAC-SHA256), Langfuse (each request as a generation, grouped by session), or any OTLP/HTTP endpoint with your headers. Batches leave within about a minute of each request and are retried on failure.
Only when you ask: include_bodies on the destination, for keys that keep request bodies. Otherwise an export carries the model, tokens, cost, latency, outcome and session, never the text.
An agent stuck repeating itself: the sixth identical tool call or request body in ten minutes is refused with 429 loop_detected. session_max_requests and session_max_spend_usd answer 429 session_cap once a session reaches them.