API keys
Almost every integration with Marea uses one kind of key: amk_user_* issued to a single Marea user, used to manage all of that user’s storefronts and products.
A second kind — mk_dev_* — exists for a separate class of caller: agents, vertical-SaaS, and agencies that create Marea accounts on behalf of other people. Most readers will never need one.
^mk_(dev|user)_[A-Za-z0-9]+$. The random suffix is 24 base62 chars (~143 bits of entropy).
The default: mk_user_* (user-key)
A user-key represents one specific Marea user and is the credential you use for everything that happens inside that user’s account.
One key covers ALL of that user’s storefronts. A user-key is owner-scoped, not storefront-scoped. The same
mk_user_* can GET / POST / PATCH / publish against every storefront the user owns — whether that’s 1 (Free plan) or 5,000 (Agency Growth plan). You do not issue a separate key per storefront. You do not pass a Storefront-Id header — the storefront is in the URL path; the key proves you own it.
How to get one:
- If you signed up at mareaalcalina.com and own a storefront, mint a
mk_user_*in one click from your dashboard at/developers/keys. - If you were bootstrapped through a partner integration, you received your
mk_user_*in thePOST /v1/usersresponse — store it then.
GET /v1/me— confirm identity, read your plan + limitsGET /v1/storefronts,POST /v1/storefronts,PATCH /v1/storefronts/:id— manage your storefrontsPOST .../products,PATCH .../products/:id,GET .../products— manage your catalogPOST .../publish— take a storefront live (gated by ToS + plan)- (after Phase B)
POST /v1/webhook_endpoints— receiveorder.*events from your store
- Bootstrap other users (that requires
developer:bootstrap, held only bymk_dev_*) - See or edit anyone else’s data — tenant boundary is encoded in the key itself
Pre-verify vs post-verify scopes
If yourmk_user_* came from a fresh POST /v1/users (partner bootstrap), it starts with a restricted scope set — me:verify, me:resendVerification, catalog:read. The only mutating calls it can make are verify and resend.
When the user submits the 6-digit code (POST /v1/users/:userId/verify), the same key is upgraded in place to catalog:read, catalog:write, storefront:publish. No rotation — store the value once at bootstrap time.
User-keys minted from the dashboard (self-issued by an already-verified user) start in the full post-verify state.
The advanced case: mk_dev_* (partner / developer key)
A mk_dev_* is for callers that act on behalf of many users — three real archetypes:
- AI agents (Claude, ChatGPT, Cursor) that bootstrap Marea accounts as part of helping their own end-users.
- Vertical SaaS (e.g., a LATAM restaurant-management product) embedding Marea so their customers get a storefront without the SaaS building one.
- Agencies running marketing for many small clients — one operator console, many client storefronts.
How to get one: Issue from the developer dashboard at mareaalcalina.com/developers/keys. The raw value is shown once; server-side only the SHA-256 hash is stored.
What you can do with it:
POST /v1/users— bootstrap a new Marea user (returns theirmk_user_*in the response)GET /v1/users,GET /v1/users/:userId— list / inspect users you’ve bootstrappedPOST /v1/users/:userId/keys— mint an additionalmk_user_*for a user you’ve bootstrapped (e.g., a second integration)- All
/v1/webhook_endpoints/*operations — manage your webhook endpoints (user.*lifecycle on accounts you bootstrapped +order.*from those accounts’ storefronts)
- Touch any user’s catalog directly. To edit a user’s storefront, use the
mk_user_*you got back from their bootstrap. Even a partner who owns a Marea storefront themselves uses their ownmk_user_*for that storefront — the dev-key never grants catalog access.
mk_dev_* can bootstrap new fake accounts and read user metadata, but can’t rewrite a single user’s prices.
Authenticating
Pass the key inAuthorization: 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.
Scopes table
Scope checks run after key lookup. Endpoints declare a required scope set; the auth layer supports bothany (one-of) and all (require-all) semantics.
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)
requiredScopes and heldScopes verbatim — the diff between them tells you exactly which kind of key you should have used (mk_user_* for catalog scopes; mk_dev_* for developer scopes).
Rotation
There is norotate call. To rotate:
- Revoke the old key.
- Issue a new one (developer dashboard for
mk_dev_*; user dashboard formk_user_*; orPOST /v1/users/:userId/keyswith a developer key for an additional user-key on a bootstrapped user). - 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_revokedon every request. - Webhook endpoints are NOT tied to a single key — they belong to your account and survive key revocation. Revoking a single key does not delete or disable any endpoint. See Webhook endpoints for the lifecycle.
- 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)
All four are 401 with
recoverable: false. Don’t loop — fix the credential.