Dashboard Get started

Why this exists

By default TokenID stores the full request and response body of every captured API call so you can audit, replay, or debug them later. For customers passing user-generated content through their LLM calls — chat apps, customer support, document Q&A — that body can contain personally identifying information. This guide covers the two switches that let you decide what gets persisted.

store_payload — drop payloads at ingest

Per-organization boolean, default true.

When store_payload=true, every event's full request + response is written to the payload JSONB column. When store_payload=false, payloads are set to NULL at ingest time — the data never reaches storage, BigQuery replica, or backups.

Set it from the dashboard at Settings → Payload Storage, or programmatically:

PATCH /api/v1/settings/organization
{
  "store_payload": false
}

After flipping, only metadata (model, provider, token counts, cost, timestamps, request_id, team_id, feature) is captured. Existing rows are not retroactively cleared — they will age out on the retention schedule.

include_payload — gate reads behind an explicit opt-in

Even when payloads are stored, all read endpoints exclude them from the response by default:

  • GET /api/v1/events/ — payload field returns null unless ?include_payload=true
  • GET /api/v1/events/{id} — same
  • GET /api/v1/events/export — same

Setting ?include_payload=true opts in for that one request. The exclusion-by-default behavior means casual dashboard browsing, exports, and most observability tooling never see the raw content.

Trade-off worth knowing

When store_payload=false, the per-event audit envelope (organization_id, user_id, api_key_id, ingested_at, audit_id) is also dropped — it lives inside payload._tokenid. Events ingested with payload off will have token counts and cost, but cannot be attributed to a specific user or API key. Choose accordingly.

Storage configuration endpoint

For data-residency requirements, point your org at a specific region and (optionally) override the blob bucket and read-replica DSN used for payload storage. This is the second half of the PII story: store_payload controls whether payloads are persisted; the storage-config endpoint controls where.

GET/api/v1/org/{org_id}/storage-config

PUT requires the admin role.

Fields

Field Type Notes
preferred_region string AWS-style region slug. One of us-east-1, us-west-2, eu-west-1, eu-central-1, ap-southeast-1, ap-northeast-1, ca-central-1
blob_bucket_override string | null Optional bucket name to receive payload blobs; max 255 chars
db_replica_dsn_secret string | null Write-only — encrypted at rest, never returned on reads
data_residency_notes string | null Free-text context (audit-friendly justification, ticket id, etc.)
# read current
curl https://token.audit.id/api/v1/org/{org_id}/storage-config \
  -H "Authorization: Bearer td_live_xxxx"

# pin to EU
curl -X PUT https://token.audit.id/api/v1/org/{org_id}/storage-config \
  -H "Authorization: Bearer td_live_xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "preferred_region": "eu-west-1",
    "data_residency_notes": "GDPR — EU customer data must not leave EU."
  }'

GET returns 404 until a config has been written for the org. Updates are upserts: the row is created on first PUT and rewritten in place thereafter.

`db_replica_dsn_secret` is encrypted on write and never returned on read — even an admin reading the config sees `null` for that field. Rotate it by issuing a fresh `PUT`.