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.
Storefronts
A storefront is the unit of catalog ownership in Marea. One user owns one or more storefronts; each has a name, a category list, products, branding, contact info, business hours, delivery settings, and a publishable hosted URL. Under the hood a storefront is theusers/{ownerUid}/menus/{menuId} document; the API surface presents it with the typed id stf_<menuId>. Internal ids never leak across the API — every handler strips the stf_ prefix at the top before any Firestore access.
| Concept | API surface | Notes |
|---|---|---|
| Storefront id | stf_<token> | Opaque, agent-stable |
| Product id | prd_<token> | Opaque, agent-stable |
| Preview link | _links.previewUrl | 24h token, anyone with the link can open |
| Public link | _links.publicUrl | null until publish; stable after publish |
| Edit link | _links.editUrl | Dashboard deep link for the owner |
Lifecycle
previewUrl can open it; the URL token expires after 24 hours. To make it public, call POST /v1/storefronts/:storefrontId/publish (see Publishing).
Creating a storefront
POST /v1/storefronts accepts a StorefrontManifest. Required scope: catalog:write (user keys only).
productsis optional in the manifest. To batch-add more after creation, use the product endpoints.- If the manifest contains more products than the plan allows, the response is
207 Multi-Statuswith the storefront created up to the plan cap plus anerrorsarray describing the over-cap items. See Plan limits. - Idempotency: send
Idempotency-Keyto make retries safe. See Safe mutations.
StorefrontDto):
_links.publicUrl is null until publish — never expose the preview URL as the “public” URL.
Updating a storefront
PATCH /v1/storefronts/:storefrontId is a partial update. Required scope: catalog:write. Three merge rules:
| Field shape | Behavior |
|---|---|
| Nested object | Deep-merge. { "delivery": { "fee": 50 } } only changes delivery.fee. |
| Array | Full-replace. { "categories": [...] } overwrites the whole array. |
Explicit null | Clears the field. { "delivery": null } removes the delivery config. |
StorefrontDto (200 OK). Republishing is a separate call — PATCH only mutates the draft.
Products
Products live on the storefront. UsePOST /v1/storefronts/:storefrontId/products to create and PATCH /v1/storefronts/:storefrontId/products/:productId to update. Both require catalog:write and accept Idempotency-Key. The per-plan product ceiling is enforced on every create; over-cap creates return 402 plan_limit with upgrade.upgradeUrl populated.
Cross-tenant access is silently denied
If yourmk_user_* key tries to access a storefront owned by a different user, the API returns 404 storefront_not_found — not 403. The 404 also fires before the empty-storefront check on publish to avoid leaking existence by status-code timing.
Common cause when you get a 404 on a stable stf_ id you used moments ago: you’re sending the wrong user key (e.g. dev environment vs. prod). Confirm with GET /v1/me which user the key acts as.
What a storefront does NOT include
- A storefront is not a channel. Where customers reach you (WhatsApp, web, in-person) is per-storefront configuration; the channel mix is not surfaced as a top-level field today.
- A storefront is not an order ledger. Orders are a separate resource (see Page webhooks for order events).
- Storefronts do not own subscriptions. Billing/plan lives on the owning user (see
/v1/me).
Limits
See Plan limits for per-plan storefront-count and product-count ceilings. The product cap is per-storefront, not per-account.Verification in code
src/api/v1/storefronts.create.tssrc/api/v1/storefronts.update.tssrc/api/v1/storefronts.publish.tssrc/api/services/translation/storefront-id.ts(stf_↔ menuId translation)src/api/services/shape/storefront.shape.ts(toStorefrontDto)