API key scopes
The 13 canonical scopes that constrain bearer tokens. Issue least-privilege keys per service.
Every Moonborn API key carries an explicit scope list. Tokens missing
the required scope for an endpoint return 403 forbidden.
The full set
| Scope | Grants |
|---|---|
* | All scopes. Owners only. |
read:personas | List personas, read persona detail, lineage, DNA, voice |
write:personas | Create, refine, fork, archive, restore personas |
read:chat | List chat sessions, read messages + memory |
write:chat | Start sessions, send messages, end sessions |
read:marketplace | List + read marketplace listings, collections |
write:marketplace | Publish, fork, install, review listings |
read:billing | Read subscription, invoices, payment methods, usage |
read:audit | Read audit log entries |
read:webhooks | List webhooks, deliveries |
write:webhooks | Create, update, delete webhooks; replay deliveries |
read:config | Read config items, snapshots, definitions |
write:config | Write config items, lock items, restore snapshots |
Least-privilege patterns
| Service | Scopes |
|---|---|
| A read-only dashboard | read:personas, read:chat, read:audit |
| A nightly sync worker | read:personas, read:chat, write:webhooks |
| A CI quality gate | read:personas, write:personas (for audit re-runs) |
| A finance ETL | read:billing |
| A compliance archiver | read:audit, read:config |
| A persona-generation worker | write:personas, read:personas |
Issue separate keys per service. Don't reuse one master key across production workloads.
Issuing a scoped key
const key = await client.apiKeys.createApiKey({
name: 'CI quality gate',
scopes: ['read:personas', 'write:personas'],
expiresAt: '2027-01-01T00:00:00Z',
});
console.log(key.plaintext);
// ⚠ Returned exactly once. Store immediately; not retrievable later.IP allowlist
Pair a key with an IP allowlist for an extra layer:
await client.apiKeys.updateApiKey({
id: key.id,
ipAllowlist: ['203.0.113.0/24'],
});Requests from outside the allowlist return 403 forbidden regardless
of scope.
Rotation
await client.apiKeys.rotateApiKey({ id: key.id });Returns a new plaintext; the old key stays valid for the configured
grace period (api.api_keys.rotation_grace_minutes, default 60).
Update consumers, then let the old key expire.
Tier
- Up to 5 keys: Free.
- Unlimited keys: Pro.
- Custom scopes / IP allowlist / rotation grace tuning: Team+.
- Per-org scope inventory (custom scopes): Enterprise.
Honest scope
API key scopes constrain API access. Workspace-level
RBAC roles constrain user
actions inside the product. They overlap — a write:personas key
issued by a Viewer-role user inherits the Viewer's read constraints
in addition to the key's scope.