4. Rate limits
Per token, sliding window, fail-open (a flaky limiter never takes the API down):
| Token type | Limit |
|---|---|
service |
10 000 / min |
human, break_glass |
1 000 / min |
Over the limit → 429 with a Retry-After header (seconds). Back off and retry.
Token types & expiry
Limits are enforced per token and per token type — the type also decides how mutations are trusted on the actions MCP surface:
UI: sign in to your team app (https://<your-team>.marduk.app) → Admin →
Settings → API Keys (/admin/settings/api-keys) → New token. Copy the
jst_… value once — it is shown only at creation and stored hashed.
Token types
| Type | Expiry | Trust (on /api/v1/mcp/actions) |
Use for |
|---|---|---|---|
service |
none (rotate manually) | trusted — mutations execute immediately | server-to-server integrations, your adjacent app's backend |
human |
1h access + 30d refresh | untrusted — mutations queue for human approval | a user acting through your app |
break_glass |
4h | untrusted | audited emergency access |
Scopes. A token carries a JSONB scope list ([{resource, actions[]}]).
Leaving it empty grants full team access (the wildcard *). Today most v1
routes require the wildcard, so least-privilege tokens are limited — see
agentic-rails.md §G-1. Scope resources include
contacts, forms, files, comms, emr, audit, tokens, *; actions are
read / write / delete / admin.
Every request is Authorization: Bearer jst_….
