driptab/Docs

Audit trail

Every write in Driptab is recorded. This page explains the two audit tables, what they capture, and how to query them.


Two tables, two purposes

billing_events — domain event log

billing_events records every mutation to a billing resource. One row per event.

Field Description
id UUIDv4
organization_id Tenant ID
project_id Project ID (most resources are project-scoped)
resource_type Type of affected object: customer, plan, subscription, invoice, etc.
resource_id UUID of the affected object
event_type Dotted code: customer.created, plan.archived, subscription.terminated, etc.
actor_token_id ID of the API token that caused the event. Null for system-generated events.
payload JSON snapshot of relevant context at the time of the event
created_at When the event was recorded

Example row:

{
  "id": "...",
  "organization_id": "org-uuid",
  "project_id": "proj-uuid",
  "resource_type": "customer",
  "resource_id": "cust-uuid",
  "event_type": "customer.created",
  "actor_token_id": "token-uuid",
  "payload": { "external_id": "emailfs_account_abc123", "name": "Ali Yilmaz" },
  "created_at": "2026-06-08T02:57:35.000Z"
}

audit_logs — HTTP access log

audit_logs records every API request, whether it succeeded or failed.

Field Description
id UUIDv4
organization_id Tenant ID
token_id ID of the token that made the request
method HTTP method: GET, POST, DELETE
path Request path: /v1/customers
status HTTP response status code
duration_ms Response time in milliseconds
ip Caller IP address
created_at When the request was received

What billing_events covers

Billing events are emitted for every resource mutation:

Event type Trigger
customer.created POST /v1/customers
plan.created POST /v1/plans
plan.archived DELETE /v1/plans/:id
charge.created POST /v1/plans/:id/charges
catalog_item.upserted POST /v1/catalog
catalog_item.archived DELETE /v1/catalog/:id
subscription.created POST /v1/subscriptions
subscription.terminated POST /v1/subscriptions/:id/terminate
invoice.created Period close (DO alarm)
payment.recorded POST /v1/payments
addon.applied POST /v1/addons/:id/apply
metric.created POST /v1/metrics

System-generated events (like invoice.created from the DO alarm) have actor_token_id: null.


Immutability guarantees

Both tables are append-only:

  • No UPDATE is ever run against them.
  • No row is deleted, even if the referenced resource is later archived or the token is revoked.
  • Cascade deletes are not enabled — historical records survive resource deletion.

This makes the audit trail suitable for compliance and dispute resolution.


Querying via the API

GET /v1/billing-events?resource_type=customer&resource_id=<uuid>
GET /v1/billing-events?event_type=plan.archived
GET /v1/billing-events?actor_token_id=<token_id>
dtab audit events --resource-type customer --resource-id <id>
dtab audit events --event-type plan.archived --since 2026-06-01

Responses are paginated with a cursor field.


Actor attribution

Every billing event records the actor_token_id. This lets you answer:

  • "Which API token deleted this plan?"
  • "Which integration created these subscriptions?"
  • "What has this MCP agent token done today?"

Combine with the token list (GET /v1/keys) to map token IDs to names.


Retention

Billing events should be retained indefinitely for financial compliance. Audit logs can be retained on a shorter schedule (e.g. 90 days). When billing_events grows large, archive older rows to R2 and query them via the R2 export format.