Skip to main content

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.
PrefixAudienceIssued byDefault scopes
mk_dev_*Agent / app developerDeveloper dashboarddeveloper:bootstrap, developer:read, developer:issueUserKey
mk_user_*A single end-userReturned 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.
ScopeHeld byUsed by
developer:bootstrapdev keysPOST /v1/users
developer:readdev keysGET /v1/users, GET /v1/users/:userId
developer:issueUserKeydev keysPOST /v1/users/:userId/keys
catalog:readuser keysGET /v1/storefronts/...
catalog:writeuser keysPOST / PATCH on storefronts and products
storefront:publishuser keysPOST /v1/storefronts/:storefrontId/publish
me:verifyrestricted userPOST /v1/users/:userId/verify
me:resendVerificationrestricted userPOST /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:
  1. Revoke the old key.
  2. 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).
  3. 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.codeWhenRecovery
missing_authorizationNeither Authorization nor X-API-Key presentAdd the header
invalid_authorization_formatHeader present but not `Bearer mk_(devuser)_…`Fix the format
key_not_foundKey not recognized (typo or never issued)Issue a new key
key_revokedKey was issued but later revokedIssue 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.