> ## 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.

# Publish storefront

> Use this when the user is ready to take their storefront live.

Publishes the current state of the storefront. Returns 402 if the plan does not permit publishing, 422 if the storefront has 0 products, 451 if ToS not accepted (PRD-7 hook). Idempotent on republish.



## OpenAPI

````yaml /openapi.json post /v1/storefronts/{storefrontId}/publish
openapi: 3.1.0
info:
  title: Marea Alcalina API
  version: 1.0.0
  description: >-
    Operations + retention API for small-business commerce. Bootstrap a digital
    menu (food) or product catalog (retail/services) plus a public hosted
    storefront for a single operator; orders flow through WhatsApp, web
    checkout, or in-person — channel is per-storefront config.


    **Auth**: `Authorization: Bearer mk_<dev|user>_...`


    **Free tier**: 1 storefront, 30 products, no publish.


    **Errors**: every non-2xx response uses the §9.6 envelope, including a
    `nextActions[]` array. Surface those verbatim to your user.


    **Rate limits**: every response carries `X-RateLimit-*` headers. 429s carry
    `Retry-After`.


    **Idempotency**: state-mutating endpoints accept an optional
    `Idempotency-Key` request header; replays within 24h return the original
    response.
  contact:
    name: Marea Alcalina API support
    url: https://developers.mareaalcalina.com
    email: developers@mareaalcalina.com
  termsOfService: https://mareaalcalina.com/terms
  license:
    name: Proprietary
    url: https://mareaalcalina.com/terms
  x-generated-at: '2026-05-15T19:15:00Z'
servers:
  - url: https://api.mareaalcalina.com
    description: Production
  - url: https://api-staging.mareaalcalina.com
    description: Staging
security:
  - BearerAuth: []
  - ApiKeyHeader: []
tags:
  - name: Identity
    description: Inspect the calling key (user or developer).
  - name: Users
    description: Bootstrap, verify, and inspect users created by a developer key.
  - name: Storefronts
    description: Create, update, and publish hosted storefronts.
  - name: Products
    description: Add and update products inside a storefront.
  - name: Webhooks
    description: Register the developer-key destination URL for user-lifecycle events.
paths:
  /v1/storefronts/{storefrontId}/publish:
    post:
      tags:
        - Storefronts
      summary: Publish storefront
      description: >-
        Use this when the user is ready to take their storefront live.


        Publishes the current state of the storefront. Returns 402 if the plan
        does not permit publishing, 422 if the storefront has 0 products, 451 if
        ToS not accepted (PRD-7 hook). Idempotent on republish.
      operationId: publishStorefront
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            Optional client-supplied key. Replays of the same key within 24h
            return the original response. Recommended for POSTs that mutate
            billing/inventory.
          schema:
            type: string
            maxLength: 200
            example: idem_b2a9f5b9-3e0c-4a5e-b3c2-7a4ce85a6b21
        - name: Accept-Language
          in: header
          required: false
          description: >-
            BCP-47 locale tag for localized error messages (`es`, `en`, `pt`).
            Defaults to `es`.
          schema:
            type: string
            example: es-MX
        - schema:
            type: string
          required: true
          name: storefrontId
          in: path
      requestBody:
        description: Request body.
        required: true
        content:
          application/json:
            schema:
              anyOf:
                - type: object
                  properties:
                    versionId:
                      type:
                        - string
                        - 'null'
                - type: object
                  properties: {}
                  additionalProperties: false
      responses:
        '200':
          description: Success.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StorefrontResponse'
        '400':
          description: Invalid request — Zod validation failed or body malformed.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '401':
          description: Auth failed — missing or invalid API key.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '402':
          description: Plan limit — the calling user's plan does not permit this action.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '403':
          description: Forbidden — key scopes do not cover this operation.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '404':
          description: Not found — leak-less; cross-tenant access also collapses here.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '409':
          description: Conflict — idempotent retry collided with a different body.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '410':
          description: Gone — verification code expired (verify endpoint).
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '413':
          description: Payload too large.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '422':
          description: >-
            Unprocessable entity — semantic precondition failed (empty
            storefront, user not verified, etc).
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '429':
          description: Rate limited — too many requests.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
            Retry-After:
              description: Seconds the client should wait before retrying.
              schema:
                type: integer
                example: 30
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '451':
          description: >-
            Unavailable for legal reasons — ToS not accepted (`code:
            tos_not_accepted`). The calling user must accept Marea's terms of
            service via the dashboard before this endpoint will succeed.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '500':
          description: Internal error.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
        '503':
          description: Service unavailable — downstream Firestore/Auth degraded.
          headers:
            X-RateLimit-Limit:
              description: >-
                Per-minute rate-limit ceiling for the calling key
                (Stripe-compatible).
              schema:
                type: integer
                example: 60
            X-RateLimit-Remaining:
              description: Remaining requests in the current per-minute window.
              schema:
                type: integer
                example: 59
            X-RateLimit-Reset:
              description: >-
                Epoch-seconds timestamp when the per-minute window rolls over
                (Stripe-compatible).
              schema:
                type: integer
                example: 1714867260
            X-Request-Id:
              description: Server-assigned request id. Echo back in support tickets.
              schema:
                type: string
                example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
      security:
        - BearerAuth:
            - storefront:publish
components:
  schemas:
    StorefrontResponse:
      type: object
      properties:
        storefront:
          $ref: '#/components/schemas/StorefrontDto'
      required:
        - storefront
    ApiErrorResponse:
      type: object
      properties:
        error:
          $ref: '#/components/schemas/ApiErrorBody'
      required:
        - error
      description: §9.6 uniform error envelope. Every non-2xx response uses this shape.
    StorefrontDto:
      type: object
      properties:
        id:
          type: string
          pattern: ^stf_
          example: stf_abc123
        name:
          type: string
        language:
          type: string
          enum:
            - es
            - en
            - pt
        currency:
          type: string
        businessType:
          type:
            - string
            - 'null'
        branding:
          type:
            - object
            - 'null'
          properties:
            logoUrl:
              type:
                - string
                - 'null'
            backgroundUrl:
              type:
                - string
                - 'null'
            theme:
              type:
                - object
                - 'null'
              properties:
                primary:
                  type:
                    - string
                    - 'null'
                secondary:
                  type:
                    - string
                    - 'null'
                tertiary:
                  type:
                    - string
                    - 'null'
              required:
                - primary
                - secondary
                - tertiary
            font:
              type:
                - string
                - 'null'
          required:
            - logoUrl
            - backgroundUrl
            - theme
            - font
        schedule:
          type:
            - object
            - 'null'
          properties:
            monday:
              type:
                - object
                - 'null'
              properties:
                open:
                  type:
                    - string
                    - 'null'
                close:
                  type:
                    - string
                    - 'null'
                closed:
                  type:
                    - boolean
                    - 'null'
              required:
                - open
                - close
                - closed
            tuesday:
              type:
                - object
                - 'null'
              properties:
                open:
                  type:
                    - string
                    - 'null'
                close:
                  type:
                    - string
                    - 'null'
                closed:
                  type:
                    - boolean
                    - 'null'
              required:
                - open
                - close
                - closed
            wednesday:
              type:
                - object
                - 'null'
              properties:
                open:
                  type:
                    - string
                    - 'null'
                close:
                  type:
                    - string
                    - 'null'
                closed:
                  type:
                    - boolean
                    - 'null'
              required:
                - open
                - close
                - closed
            thursday:
              type:
                - object
                - 'null'
              properties:
                open:
                  type:
                    - string
                    - 'null'
                close:
                  type:
                    - string
                    - 'null'
                closed:
                  type:
                    - boolean
                    - 'null'
              required:
                - open
                - close
                - closed
            friday:
              type:
                - object
                - 'null'
              properties:
                open:
                  type:
                    - string
                    - 'null'
                close:
                  type:
                    - string
                    - 'null'
                closed:
                  type:
                    - boolean
                    - 'null'
              required:
                - open
                - close
                - closed
            saturday:
              type:
                - object
                - 'null'
              properties:
                open:
                  type:
                    - string
                    - 'null'
                close:
                  type:
                    - string
                    - 'null'
                closed:
                  type:
                    - boolean
                    - 'null'
              required:
                - open
                - close
                - closed
            sunday:
              type:
                - object
                - 'null'
              properties:
                open:
                  type:
                    - string
                    - 'null'
                close:
                  type:
                    - string
                    - 'null'
                closed:
                  type:
                    - boolean
                    - 'null'
              required:
                - open
                - close
                - closed
          required:
            - monday
            - tuesday
            - wednesday
            - thursday
            - friday
            - saturday
            - sunday
        delivery:
          type:
            - object
            - 'null'
          properties:
            enabled:
              type: boolean
            type:
              type:
                - string
                - 'null'
              enum:
                - fixed
                - distance
            fixedPrice:
              type:
                - number
                - 'null'
            ranges:
              type:
                - array
                - 'null'
              items:
                type: object
                properties:
                  fromKm:
                    type: number
                  toKm:
                    type:
                      - number
                      - 'null'
                  price:
                    type: number
                required:
                  - fromKm
                  - toKm
                  - price
          required:
            - enabled
            - type
            - fixedPrice
            - ranges
        pickup:
          type:
            - boolean
            - 'null'
        dineIn:
          type:
            - boolean
            - 'null'
        whatsapp:
          type:
            - string
            - 'null'
        biography:
          type:
            - object
            - 'null'
          properties:
            title:
              type: string
            description:
              type: string
          required:
            - title
            - description
        categories:
          type:
            - array
            - 'null'
          items:
            type: object
            properties:
              name:
                type: string
              position:
                type:
                  - integer
                  - 'null'
            required:
              - name
              - position
        slug:
          type:
            - string
            - 'null'
        published:
          type:
            - boolean
            - 'null'
        _links:
          $ref: '#/components/schemas/StorefrontLinks'
        createdAt:
          type:
            - string
            - 'null'
        updatedAt:
          type:
            - string
            - 'null'
      required:
        - id
        - name
        - language
        - currency
        - businessType
        - branding
        - schedule
        - delivery
        - pickup
        - dineIn
        - whatsapp
        - biography
        - categories
        - slug
        - published
        - _links
        - createdAt
        - updatedAt
    ApiErrorBody:
      type: object
      properties:
        type:
          type: string
          enum:
            - rate_limited
            - invalid_request
            - auth
            - not_found
            - plan_limit
            - internal
            - conflict
            - idempotency_conflict
            - service_unavailable
            - tos_not_accepted
          description: High-level error category. Agents branch on this.
          example: auth
        code:
          type: string
          description: Stable machine-readable code.
          example: missing_authorization
        message:
          type: string
          description: Human-readable, localized via Accept-Language.
        doc:
          type: string
          description: Link to docs for this error code.
        param:
          type:
            - string
            - 'null'
        requestId:
          type: string
          example: req_30a9358b-70bd-44f3-aa5d-8983b558ad84
        requestLogUrl:
          type: string
        recoverable:
          type: boolean
        retryAfterMs:
          type:
            - integer
            - 'null'
        nextActions:
          type: array
          items:
            $ref: '#/components/schemas/ApiNextAction'
        upgrade:
          $ref: '#/components/schemas/ApiErrorUpgrade'
        requiredScopes:
          type: array
          items:
            type: string
        heldScopes:
          type: array
          items:
            type: string
      required:
        - type
        - code
        - message
        - doc
        - param
        - requestId
        - requestLogUrl
        - recoverable
        - retryAfterMs
        - nextActions
        - upgrade
    StorefrontLinks:
      type: object
      properties:
        previewUrl:
          type:
            - string
            - 'null'
        editUrl:
          type:
            - string
            - 'null'
        publicUrl:
          type:
            - string
            - 'null'
      required:
        - previewUrl
        - editUrl
        - publicUrl
    ApiNextAction:
      type: object
      properties:
        label:
          type: string
          example: Validate the JSON before retrying.
        method:
          type:
            - string
            - 'null'
          example: null
        url:
          type:
            - string
            - 'null'
          example: null
      required:
        - label
        - method
        - url
      description: A concrete action the agent can offer the user.
    ApiErrorUpgrade:
      type:
        - object
        - 'null'
      properties:
        currentPlan:
          type: string
          example: free
        requiredPlan:
          type: string
          example: pro
        upgradeUrl:
          type: string
          example: https://mareaalcalina.com/upgrade?planSource=api
        previewUrl:
          type: string
          description: Optional preview link the agent can surface.
      required:
        - currentPlan
        - requiredPlan
        - upgradeUrl
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: mk_dev_* | mk_user_*
      description: >-
        Marea API key. `mk_dev_*` keys are developer-scoped (bootstrap, list
        users, register webhook). `mk_user_*` keys are user-scoped (manage that
        one user's storefronts/products). Scopes: `catalog:read`,
        `catalog:write`, `storefront:publish`, `me:verify`,
        `me:resendVerification`, `developer:bootstrap`, `developer:read`,
        `developer:issueUserKey`, `developer:webhooks`.
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: >-
        Alternative to `Authorization: Bearer`. Same `mk_*` value. Use only when
        your environment cannot send the `Authorization` header.

````