Public API: Audit & Observability
Every state-changing request authenticated by a service token leaves a trail you can audit, query, and stream. This page covers four signals: the in-app audit log, structured server-side logs, the rate-limit headers on every response, and webhooks for state-change subscriptions.
Audit log entries for API actions
Every write that authenticates with a service token produces an audit entry alongside the resource change. The entry records:
actorType: API_TOKEN— distinguishes API actions from dashboard (USER) and system actions.source: API— the channel that triggered the action. Other values:DASHBOARD,CLI,SYSTEM.metadata.tokenId+metadata.tokenName— the specific token row that authenticated the request. The token's display name is preserved even if you later rotate the secret.ip+userAgent— the calling client's observable identity.before/after— JSON diff of the resource (where applicable).
audit:read scope or org admin access.Viewing audit entries in-app
The dashboard ships a dedicated audit-log view at /audit-log. Open it from the organisation sidebar, or link directly:
1https://app.avsb.cloud/audit-logFilters available in the UI:
- Actor type — User, API token, System.
- Source — Dashboard, API, CLI, System.
- Specific token — pick one of your service tokens to see only its actions.
- Resource type — Project, Experiment, Flag, Audience, etc.
- Time range — last hour through last 90 days.
Querying audit entries via the API
You can read the audit log itself through the API with the audit:read scope. Filter by token to track exactly what each service identity has done:
1curl 'https://app.avsb.cloud/api/orgs/<orgId>/audit-log?actorType=API_TOKEN&tokenId=tok_abc&limit=100' \2 -H "Authorization: Bearer avsb_svc_..."Sample response row:
1{2 "id": "audit_01HX...",3 "createdAt": "2026-05-17T13:24:00Z",4 "actorType": "API_TOKEN",5 "actorId": "tok_abc",6 "actorName": "Terraform CI",7 "source": "API",8 "action": "experiment.update",9 "resourceType": "EXPERIMENT",10 "resourceId": "exp_def",11 "ip": "203.0.113.42",12 "userAgent": "terraform-provider-avsb/0.4.1",13 "metadata": { "tokenId": "tok_abc" },14 "before": { "trafficPct": 50 },15 "after": { "trafficPct": 80 }16}Structured server-side logging
Every public-API request is logged server-side via pino. Each log line is a single JSON object suitable for ingestion into your log pipeline (Datadog, Sumo, ELK, BetterStack, Axiom, etc.). Guaranteed fields:
requestId— opaque id, also echoed in theX-Request-Idresponse header so you can correlate.method+path+status+latencyMs.orgId— from the URL.tokenId— the authenticating service token (omitted for unauthenticated requests).scope— the specific scope evaluated for the request.idempotencyKey— when supplied.idempotencyReplayed—truewhen the response was served from the idempotency cache.
Rate-limit headers as observability signal
Every response carries the standard rate-limit headers — graph them in your observability stack to spot capacity issues before they turn into 429s:
X-RateLimit-Limit— current quota (requests/minute) for this token + scope family.X-RateLimit-Remaining— alarm onremaining/limit < 0.1.X-RateLimit-Reset— unix timestamp; use to drive token-bucket back-off.Retry-After— present only on429responses; respect it before retrying.
1// Forward rate-limit headers into your metrics pipeline2function recordRateLimit(res) {3 metrics.gauge('avsb_api.rate_limit.remaining', Number(res.headers.get('X-RateLimit-Remaining')))4 metrics.gauge('avsb_api.rate_limit.limit', Number(res.headers.get('X-RateLimit-Limit')))5}Webhooks for state changes
For push-based observability — i.e. you want to be told when a resource changes rather than polling the audit log — subscribe to webhooks. Webhooks are configured per-project (snippet / experiment events) and per-org (token, flag, member events).
Event types relevant to API-token activity:
api_token.created/.rotated/.revokedexperiment.published/.paused/.completedflag.rule.published/.archivedaudit.entry.created— every audit entry, in real time.
1curl https://app.avsb.cloud/api/orgs/<orgId>/webhooks \2 -X POST \3 -H "Authorization: Bearer avsb_svc_..." \4 -H "Content-Type: application/json" \5 -d '{6 "url": "https://hooks.your-host/avsb",7 "events": ["audit.entry.created"],8 "secret": "whsec_..."9 }'Every webhook delivery is signed with an HMAC-SHA256 of the body keyed by your secret, passed as the X-AvsB-Signature header. Reject deliveries with an invalid signature.
id header. See the Webhooks guide for the full signing flow, retry schedule, and replay UI.