Events
Query the raw event log of every captured AI API call.
List events
/api/v1/eventsReturns a paginated list of captured API calls.
Query parameters
| Parameter | Type | Description |
|---|---|---|
session_id |
string | Filter by session ID |
provider |
string | Filter by provider: anthropic, openai, xai, google, aws_bedrock, azure_openai, cohere, mistral |
model |
string | Filter by model name |
team_id |
string | Filter by team identifier (passed at ingest) |
feature |
string | Filter by feature label (passed at ingest) |
since |
ISO 8601 | Start of time range |
until |
ISO 8601 | End of time range |
limit |
integer | Max results (default 100, max 1000) |
offset |
integer | Pagination offset |
include_payload |
boolean | Include raw request/response body. Default false for PII safety |
Response
{
"events": [
{
"id": "evt_01abc…",
"provider": "anthropic",
"model": "claude-opus-4-7",
"session_id": "my-session",
"team_id": "platform-ai",
"feature": "rag-rerank",
"is_batch": false,
"batch_id": null,
"input_tokens": 1024,
"output_tokens": 256,
"cache_read": 800,
"cache_creation": 224,
"reasoning_tok": 0,
"cached_tok": 0,
"cost_usd": 0.0043,
"duration_ms": 1240,
"stop_reason": "end_turn",
"payload": null,
"timestamp": "2026-05-04T08:00:00Z"
}
],
"count": 1,
"offset": 0
}
Batch API pricing
When an event has is_batch=true (set automatically by the SDK wrappers when they detect an
Anthropic Message Batches or OpenAI Batch API response), cost_usd is computed at 50% of the
standard per-token rate. The batch_id field carries the upstream batch identifier so you can
correlate events that belong to the same batch.
Team and feature attribution
team_id and feature are optional ingest-time labels for sub-organization cost attribution.
Pass them as kwargs on the SDK wrapper:
client = JournaledAnthropic(
api_key="sk-ant-…",
team_id="platform-ai",
feature="rag-rerank",
)
Both columns are indexed and queryable on GET /api/v1/events/?team_id=…&feature=… and on the
dashboard breakdown endpoints (?team_id=… / ?feature=…).
Payload visibility
payload is excluded from responses by default. Pass ?include_payload=true to receive the raw
JSONB body. See PII controls for the org-level toggle that drops
payloads at ingest entirely.
Trace ingest
/api/v1/ingest/traceGeneric OpenTelemetry-style trace ingest for callers who can't use the SDK wrappers — for
example, a service already emitting OTLP/JSON via the OpenTelemetry collector. The body is the
standard OTLP resourceSpans shape; TokenID reads the gen_ai.* semantic-convention attributes
off each span and writes one otel_span event row per span.
curl -X POST https://token.audit.id/api/v1/ingest/trace \
-H "Authorization: Bearer td_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"resourceSpans": [{
"scopeSpans": [{
"spans": [{
"name": "anthropic.messages.create",
"startTimeUnixNano": "1748044800000000000",
"endTimeUnixNano": "1748044801240000000",
"attributes": [
{"key": "gen_ai.system", "value": {"stringValue": "anthropic"}},
{"key": "gen_ai.request.model", "value": {"stringValue": "claude-opus-4-7"}},
{"key": "gen_ai.usage.input_tokens", "value": {"intValue": "1024"}},
{"key": "gen_ai.usage.output_tokens", "value": {"intValue": "256"}},
{"key": "gen_ai.response.cost_usd", "value": {"doubleValue": 0.0043}},
{"key": "gen_ai.response.id", "value": {"stringValue": "req_011abc"}}
]
}]
}]
}]
}'
Returns 202 Accepted with {"accepted": N, "organization_id": "…"}. Workspace-scoped keys
must carry the ingest permission.
Langfuse ingest
/api/v1/ingest/langfuseCompatibility shim for teams already instrumented for Langfuse. Accepts a Langfuse
observation-create webhook payload and writes one langfuse_generation event row per
GENERATION-type observation. Other observation types are accepted but ignored (accepted: 0).
curl -X POST https://token.audit.id/api/v1/ingest/langfuse \
-H "Authorization: Bearer td_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "observation-create",
"body": {
"id": "obs_abc",
"type": "GENERATION",
"model": "claude-opus-4-7",
"startTime": "2026-05-21T10:30:00Z",
"latency": 1240,
"usage": {"input": 1024, "output": 256},
"metadata": {"feature": "rag-rerank"}
}
}'
Point your Langfuse instance's outbound webhook at this URL with the org API key as a Bearer
token. The X-Langfuse-Signature header is accepted but not verified — auth is on the bearer
token.
Ingest behavior
Two cross-cutting behaviors apply to every ingest path, including the SDK wrappers and the two endpoints above.
Deduplication
A unique constraint on (organization_id, provider, model, api_key_hash, timestamp) rejects
replays. The api_key_hash is a 16-char SHA-256 derived from the ingest API key id and the
event's request_id (or session_id + model + timestamp as a fallback). On conflict, the
duplicate row is silently skipped via ON CONFLICT DO NOTHING. SDK retries on transient
failures are therefore safe — you cannot double-bill yourself by retrying.
NUL-byte stripping
PostgreSQL rejects \x00 in UTF-8 text columns, so the ingest path strips every character
outside [\t\n\r\x20-\x7E] from every string field — and recursively from every nested string
value in payload, tool_input, tool_output, and the _tokenid block. Numeric fields
(token counts, cost, duration) are untouched. The stripping is invisible in normal use; if
you're searching for events containing control characters or non-ASCII content, expect it to
have been removed at the boundary.