Authentication
The API uses tenant-scoped Bearer tokens. One token = one organization = one tenant context.
The dashboard and oRPC tier authenticate with auth.js (next-auth) — email + password by default (sign in at /sign-in). The only required auth env var is AUTH_SECRET (alongside DATABASE_URL); generate it with openssl rand -base64 32. Clerk is an optional VOCION_AUTH_PROVIDER=clerk path for hosted/cloud builds, not the default.
Issuing a token
Dashboard: Admin → API tokens → Create token
A token carries:
| Field | Notes |
|---|---|
name | Human-readable label (e.g. "field-notes-mobile-app") |
scope | Default read:all,run:invoke. Can narrow to e.g. read:skills,run:invoke |
expiresAt | Optional. Default: no expiry. Rotate routinely for production systems |
The token is shown once at creation. Store it in your secret manager; the dashboard only keeps a vcn_live_... prefix and a hash after that.
Format
vcn_live_<token-id>_<secret>
The <token-id> is a stable public handle (safe to log / show in the dashboard); the <secret> is stored only as a SHA-256 hash. Prefix signals environment: vcn_live_ for production, vcn_test_ for non-production.
Sending requests
Authorization: Bearer vcn_live_...
Tokens are principals
A token isn't just an authentication credential — it resolves to a permission principal: a role, a set of action grants, and an org scope. Every write the token makes is authorized against the same model as a human user and lands in the same review queue. There is no separate "service account" authorization path. Deciding a review (POST /api/v1/reviews/decide), for instance, requires the approve capability — a token without it is rejected before anything happens.
Scopes
| Scope | What it permits |
|---|---|
read:all | GET on any resource or run within the tenant |
read:skills | Narrow: only GET /agents, /skills |
write:resources | POST/PATCH on resource CRUD (equivalent to workspace-as-code writes) |
run:invoke | POST /skills/:slug/runs, POST /workflows/:slug/runs |
run:approve | Approve/reject pending runs |
Default new token: read:all,run:invoke. Widen or narrow per use case.
Rate limits
- Default: 60 requests/minute per token
- Bursts up to 120 tolerated
X-RateLimit-Remaining+X-RateLimit-Resetheaders on every response- 429 with
Retry-Afterwhen exceeded
Enterprise tier: raise limits or disable entirely.
Rotation
# Create new token, test, then revoke old
curl -H "Authorization: Bearer $NEW_TOKEN" https://.../api/v1/agents
# If good:
curl -X DELETE -H "Authorization: Bearer $NEW_TOKEN" \
https://.../api/v1/tokens/$OLD_TOKEN_ID
Revocation is instant — no grace period.
Token audit
Every API call records api_token_id on the skill_run / workflow_run / audit_event it produced. Full trail: who (token) triggered what, when, and what happened.