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.
AGENTS.md — Marea Alcalina API
Following the agents.md spec. This file is for AI agents (Claude, GPT, Cursor, Continue.dev, generic LLM-driven tools) consuming the Marea public API. For the full doc index in agent-friendly markdown form, fetch llms.txt.
What this API is for
Operations + retention API for small-business commerce. Bootstrap users, manage storefronts + products (food menus or retail / service catalogs), publish to public hosted URLs. End-customer order channels are the operator’s choice — WhatsApp, web checkout, or in-person pickup — and configurable per storefront. The API does not lock the channel.Auth model
Two-tier (see Two-tier keys for the full model):mk_dev_*— developer key, held by the agent or app builder. Holdsdeveloper:bootstrap,developer:read,developer:issueUserKey. Defaultrpd: 50(configurable at issue time; the devrpdIS the bootstrap cap, not a separate quota).mk_user_*— per-user key, returned byPOST /v1/usersand scoped to one user. Issued restricted (onlyme:verify+me:resendVerification) until the 6-digit code is verified, then upgraded in-place to full catalog scopes (catalog:read,catalog:write,storefront:publish). Cannot bootstrap, cannot see other users’ data.
Authorization: Bearer <key> (or X-API-Key: <key> as a fallback). The split lets an agent bootstrap users with its own dev key and receive a per-user key in the response — the agent never holds the user’s password.
Common patterns
- Bootstrap → verify → use.
POST /v1/usersreturns a restrictedmk_user_*key + emails the user a 6-digit code. The user reads the code aloud (or the agent fetches it via Gmail-MCP), agent callsPOST /v1/users/:userId/verify, the same key is upgraded to full per-user scope. See Bootstrap quickstart. - Idempotency on every mutation. Pass
Idempotency-Key: <uuid-v4>on everyPOSTandPATCH. Same key + same body returns the original response (replay-safe). Same key + different body returns409 idempotency_conflict. See Safe mutations. - Branch on
error.type, noterror.message. Thetypefield is a stable 10-value enum;messageis localized and may change. See Errors. - Surface
nextActions[]verbatim. Every error returns{ label, method, url }[]— these are the concrete actions the user can take. Don’t paraphrase; render verbatim. - Read rate-limit headers proactively.
X-RateLimit-Remainingis on every response. When you hit429, readRetry-After(seconds) and back off. Defaults:rpm: 60. Dev keys:rpd: 50. User keys:rpd: 10000. - Markdown for ingestion. Every doc page also serves at
<page>.md(e.g.,/concepts/errors.md); use that variant when ingesting docs into your context — cleaner than the HTML.
When to call which tool
REST (always available) and MCP tool (when the user has installed the Marea MCP server in Claude Desktop / Cursor / Continue.dev — see MCP install quickstart).| Goal | REST | MCP tool |
|---|---|---|
| Bootstrap a new user | POST /v1/users (dev key) | marea.bootstrap_user |
| Verify the 6-digit email code | POST /v1/users/:userId/verify | (use REST in v1) |
| Read identity / plan / budget | GET /v1/me | marea.whoami |
| Create a storefront | POST /v1/storefronts | marea.create_storefront |
| Update storefront fields | PATCH /v1/storefronts/:id | marea.update_storefront |
| Add a product | POST /v1/storefronts/:id/products | marea.create_product |
| Update a product | PATCH /v1/storefronts/:id/products/:productId | marea.update_product |
| Publish to public URL (needs user confirmation) | POST /v1/storefronts/:id/publish | marea.publish_storefront (fires MCP elicitation) |
What NOT to do
- Don’t swallow
nextActions[]. The most common agent failure mode is silently retrying past a 402 (paywall) or 451 (ToS not accepted) without ever surfacing the action to the user. Render the array verbatim. - Don’t auto-accept the ToS on the user’s behalf. A 451 → modal flow requires user input by design. The agent cannot bypass.
- Don’t bootstrap past your dev key’s
rpdcap. Default is 50/day (configurable at issue time). Hitting it returns 429rate_limitedwithcode: rate_limit_exceededandrpd_exceededinerror.message. ReadRetry-After(seconds-until-the-day-rolls-over) and back off. - Don’t call publish without explicit user confirmation. Publish is destructive and user-visible. Use MCP elicitation if you have the MCP tool; otherwise prompt the user explicitly.
- Don’t cache
mk_user_*keys across users or sessions. Per-user keys belong in the user’s own context. - Don’t poll verification status faster than the API allows. The user-facing rate limit is
rpm: 60per user-key. Poll at most once every 30s during the verify window; better, subscribe to theuser.verifiedagent webhook on the developer key — see Agent webhooks. - Don’t reuse the same
Idempotency-Keywith a different body. That returns409 idempotency_conflictand you must generate a fresh key. If you’re retrying with edits, that’s a new request — new key. - Don’t branch on the localized
error.message. Branch onerror.type(stable enum) orerror.code(stable string).
Errors
Every error follows the same envelope:{ type, code, message, doc, requestId, recoverable, retryAfterMs, nextActions, upgrade, requiredScopes? }. Branch on error.type. The 10 stable types:
error.type | Typical HTTP | Surface to user? | Retry? | What to do |
|---|---|---|---|---|
rate_limited | 429 | No (transparent) | Yes after retryAfterMs | Sleep + retry same request + same Idempotency-Key |
invalid_request | 400 / 410 | No (fix client-side) | No | Fix the body. Includes invalid_idempotency_key, idempotency_snapshot_unavailable |
auth (401) | 401 | Maybe | No | Re-prompt for a valid key. Codes: missing_authorization, invalid_authorization_format, key_not_found, key_revoked |
auth (insufficient scope) | 403 | Maybe | No | Read requiredScopes + heldScopes arrays; ask user/dev for a key with the right scope |
not_found | 404 | Maybe | No | Confirm the id. May also be a silent cross-tenant denial if the calling key doesn’t own the resource |
plan_limit | 402 | Yes (paywall) | No | Surface error.upgrade.upgradeUrl verbatim. The user must upgrade, then retry |
internal | 500 | Yes (with requestId) | Once with backoff | Then escalate. Surface requestId so support can trace |
conflict | 409 | No | Yes after 1s | idempotency_in_flight — the same key is still processing. Retry with same key |
idempotency_conflict | 409 | No | Yes with new Idempotency-Key | Same key was used earlier with a different body. Generate a fresh UUID |
service_unavailable | 503 | Yes (after retries) | Yes with backoff | Exponential backoff |
tos_not_accepted | 451 | Yes (link to dashboard) | After user accepts | Surface nextActions[0].url (modal). Agent cannot bypass |
Where to find docs
- llms.txt index: https://docs.mareaalcalina.com/llms.txt — agent-curated overview of the entire surface
- llms-full.txt: https://docs.mareaalcalina.com/llms-full.txt — concatenation of all pages (Mintlify auto-emits in production)
- Per-page markdown:
https://docs.mareaalcalina.com/<page>.md(e.g.,/concepts/errors.md) - OpenAPI 3.1 spec: https://api.mareaalcalina.com/v1/openapi.json — Zod-derived from the cloud-functions code; 5-min cached
- Postman collection: https://docs.mareaalcalina.com/marea.postman.json — auto-generated from the OpenAPI spec
- MCP server: https://mcp.mareaalcalina.com — paste-token install for Claude Desktop / Cursor / Continue.dev; 7
marea.*tools (verify + resend are deliberately REST-only) - API catalog (RFC 9727): https://mareaalcalina.com/.well-known/api-catalog — discoverability for agent crawlers
Conventions
- Locale:
Accept-Languageis honored. Defaultes-MX. PassAccept-Language: enfor English error messages,ptfor Portuguese. - Currency: configurable per storefront. Pass
currency: "MXN" | "USD" | "CAD" | "BRL" | ...on storefront create. - Phone format: E.164 (
+52...). - Timestamps: ISO 8601 strings.
- IDs: prefixed (
usr_,stf_,prd_,dev_).