Documentation Index
Fetch the complete documentation index at: https://docs.mareaalcalina.com/llms.txt
Use this file to discover all available pages before exploring further.
API keys
Marea uses two key types. Both authenticate the same way; their capabilities differ. The split is load-bearing for agent UX: an agent holds its own mk_dev_* key and uses it to bootstrap end-users — each end-user gets a per-user mk_user_* key scoped to that one user.
| Prefix | Audience | Issued by | Default scopes |
|---|
mk_dev_* | Agent / app developer | Developer dashboard | developer:bootstrap, developer:read, developer:issueUserKey |
mk_user_* | A single end-user | Returned by POST /v1/users (bootstrap) | catalog:read, me:verify, me:resendVerification (pre-verify) → catalog:read, catalog:write, storefront:publish (post-verify) |
Format is locked: ^mk_(dev|user)_[A-Za-z0-9]+$. The random suffix is 24 base62 chars (~143 bits of entropy).
Authenticating
Pass the key in Authorization: Bearer <key> (preferred). X-API-Key: <key> is accepted as a fallback. Any other header — or a non-Bearer Authorization scheme — fails with invalid_authorization_format.
GET /v1/me HTTP/1.1
Host: api.mareaalcalina.com
Authorization: Bearer mk_user_abc123...
Scopes
Scope checks run after key lookup. Endpoints declare a required scope set; the auth layer supports both any (one-of) and all (require-all) semantics.
| Scope | Held by | Used by |
|---|
developer:bootstrap | dev keys | POST /v1/users |
developer:read | dev keys | GET /v1/users, GET /v1/users/:userId |
developer:issueUserKey | dev keys | POST /v1/users/:userId/keys |
catalog:read | user keys | GET /v1/storefronts/... |
catalog:write | user keys | POST / PATCH on storefronts and products |
storefront:publish | user keys | POST /v1/storefronts/:storefrontId/publish |
me:verify | restricted user | POST /v1/users/:userId/verify |
me:resendVerification | restricted user | POST /v1/users/:userId/resendVerification |
GET /v1/me accepts any of the user scopes; developer keys bypass the scope check entirely (a developer key always sees its own identity).
Scope mismatch (403)
{
"error": {
"type": "auth",
"code": "insufficient_scope",
"message": "Missing required scopes: catalog:write.",
"requiredScopes": ["catalog:write"],
"heldScopes": ["catalog:read"],
"recoverable": false
}
}
Surface requiredScopes and heldScopes verbatim — agents use the diff to either re-prompt the user or request an upscoped key.
Issuance
Developer keys
Issued from the developer dashboard at mareaalcalina.com/developers/keys. The raw key is returned once, server-side only the SHA-256 hash is stored. If you lose the raw value, revoke and issue a new one. The default per-developer bootstrap quota is 50 / day (see Rate limits).
User keys (bootstrap)
A mk_user_* key is created automatically by POST /v1/users and returned once in the bootstrap response. It starts in a restricted scope set (catalog:read, me:verify, me:resendVerification) — the only mutating calls it can make are verify / resend. On successful verification (POST /v1/users/:userId/verify), the same key is upgraded in place to the full user scope set (catalog:read, catalog:write, storefront:publish). There is no key rotation across verify — store the value once. See Verification flow.
Additional user keys
To issue a second user key for an already-verified user (e.g. a separate integration), call POST /v1/users/:userId/keys with your developer key. You can only mint keys for users you bootstrapped — cross-developer attempts return 404 user_not_found (leak-less).
Rotation
There is no rotate call. To rotate:
- Revoke the old key.
- Issue a new one (developer dashboard for
mk_dev_*, the user dashboard for mk_user_*, or POST /v1/users/:userId/keys for a developer minting an additional user key).
- Update your client.
Revocation
Revoked keys stop authenticating within ~60s end-to-end (the negative-lookup cache TTL). After revocation:
- The key returns
401 key_revoked on every request.
- Any per-key webhook URL is cleared (no orphan delivery surface if the same key id is ever re-issued).
- Revocation is non-cascading: revoking a developer key does NOT revoke the user keys it minted. To wipe everything for an owner, the owner-scoped revoke-all path is used (operator path; not in the public API).
Auth errors (401)
error.code | When | Recovery | |
|---|
missing_authorization | Neither Authorization nor X-API-Key present | Add the header | |
invalid_authorization_format | Header present but not `Bearer mk_(dev | user)_…` | Fix the format |
key_not_found | Key not recognized (typo or never issued) | Issue a new key | |
key_revoked | Key was issued but later revoked | Issue a new key | |
All four are 401 with recoverable: false. Don’t loop — fix the credential.
Server-side storage
- The raw key is never stored. Only the SHA-256 hash + a 12-char safe prefix (for dashboard display + logs).
- Authentication uses constant-time comparison.
lastUsedAt is best-effort, throttled to at most one write per minute per key. Do not use it for security decisions; it may lag.
- Positive auth lookups are cached 30s per instance; revocations propagate within 60s.
Verification in code
The handlers and service that own this surface:
src/api/middleware/apiKey.ts — extract + verify.
src/api/services/apiKey.service.ts — issuance, revocation, lookup, scope upgrade.
src/api/services/scope.constants.ts — canonical scope sets.