{"openapi":"3.1.0","info":{"title":"Marea Alcalina API","version":"1.0.0"},"servers":[{"url":"https://api.mareaalcalina.com"}],"components":{"schemas":{"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"]},"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"]},"ApiErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ApiErrorBody"}},"required":["error"],"description":"§9.6 uniform error envelope. Every non-2xx response uses this shape."},"MePlanLimits":{"type":"object","properties":{"storefronts":{"type":"integer","minimum":0},"products":{"type":"integer","minimum":0},"publishable":{"type":"boolean"}},"required":["storefronts","products","publishable"]},"MePlan":{"type":["object","null"],"properties":{"tier":{"type":"string","enum":["free","basic","pro","business"],"description":"Plan tier the calling user is on. Numeric internal plans map to one of these 4.","example":"free"},"limits":{"$ref":"#/components/schemas/MePlanLimits"}},"required":["tier","limits"]},"MeRateLimit":{"type":"object","properties":{"rpm":{"type":"integer","exclusiveMinimum":0,"example":60},"rpd":{"type":"integer","exclusiveMinimum":0,"example":10000},"remainingMinute":{"type":"integer","minimum":0},"remainingDay":{"type":"integer","minimum":0}},"required":["rpm","rpd","remainingMinute","remainingDay"]},"MeLinks":{"type":"object","properties":{"upgradeUrl":{"type":["string","null"]},"dashboardUrl":{"type":["string","null"]},"developerDashboardUrl":{"type":["string","null"]}}},"MeResponse":{"type":"object","properties":{"id":{"type":"string","example":"usr_abc123"},"type":{"type":"string","enum":["user","developer"]},"email":{"type":"string"},"displayName":{"type":"string"},"verificationStatus":{"type":["string","null"],"enum":["pending","verified"]},"tosAcceptedAt":{"type":["string","null"]},"plan":{"$ref":"#/components/schemas/MePlan"},"planQuantity":{"type":["integer","null"],"exclusiveMinimum":0},"rateLimit":{"$ref":"#/components/schemas/MeRateLimit"},"keyId":{"type":["string","null"]},"_links":{"$ref":"#/components/schemas/MeLinks"}},"required":["id","type","email","displayName","rateLimit","keyId","_links"],"description":"Identity + plan info for the calling key. Available to both user and developer keys (branched by `type`)."},"StorefrontLinks":{"type":"object","properties":{"editUrl":{"type":["string","null"]},"publicUrl":{"type":["string","null"]}},"required":["editUrl","publicUrl"]},"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"]},"PartialProductError":{"type":"object","properties":{"type":{"type":"string","enum":["plan_limit"]},"code":{"type":"string","enum":["products_over_limit"]},"message":{"type":"string"},"param":{"type":"string","enum":["products"]},"doc":{"type":"string"},"recoverable":{"type":"boolean","enum":[true]},"recovery":{"type":"object","properties":{"skippedCount":{"type":"integer","minimum":0},"skippedProducts":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":0},"title":{"type":["string","null"]}},"required":["index","title"]}},"upgrade":{"type":"object","properties":{"currentPlan":{"type":"string"},"requiredPlan":{"type":"string"},"upgradeUrl":{"type":"string"}},"required":["currentPlan","requiredPlan","upgradeUrl"]}},"required":["skippedCount","skippedProducts","upgrade"]}},"required":["type","code","message","param","doc","recoverable","recovery"]},"StorefrontCreateResponse":{"type":"object","properties":{"storefront":{"$ref":"#/components/schemas/StorefrontDto"},"errors":{"type":"array","items":{"$ref":"#/components/schemas/PartialProductError"}}},"required":["storefront"]},"StorefrontResponse":{"type":"object","properties":{"storefront":{"$ref":"#/components/schemas/StorefrontDto"}},"required":["storefront"]},"ExtraProductOption":{"type":"object","properties":{"title":{"type":"string"},"price":{"type":"number","minimum":0},"available":{"type":"boolean"},"stock":{"type":["integer","null"]}},"required":["title","price","available"]},"ExtraProductsCategory":{"type":"object","properties":{"title":{"type":"string"},"obligatory":{"type":"boolean"},"multipleOption":{"type":"boolean"},"maxOptions":{"type":"integer"},"minOptions":{"type":"integer"},"extraProducts":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ExtraProductOption"}}},"required":["title","obligatory","multipleOption","maxOptions","minOptions"]},"ProductDto":{"type":"object","properties":{"id":{"type":"string","pattern":"^prd_","example":"prd_abc123"},"title":{"type":"string"},"description":{"type":["string","null"]},"price":{"type":"number"},"salePrice":{"type":["number","null"]},"category":{"type":["string","null"]},"subcategory":{"type":["string","null"]},"imageUrl":{"type":["string","null"]},"thumbnailUrl":{"type":["string","null"]},"sku":{"type":["string","null"]},"slug":{"type":["string","null"]},"position":{"type":["integer","null"]},"cartProduct":{"type":["boolean","null"]},"hide":{"type":["boolean","null"]},"stock":{"type":["integer","null"]},"tags":{"type":["array","null"],"items":{"type":"string"}},"extraProductsCategory":{"type":["array","null"],"items":{"$ref":"#/components/schemas/ExtraProductsCategory"}},"imageProcessingPending":{"type":["boolean","null"]},"createdAt":{"type":["string","null"]},"updatedAt":{"type":["string","null"]}},"required":["id","title","description","price","salePrice","category","subcategory","imageUrl","thumbnailUrl","sku","slug","position","cartProduct","hide","stock","tags","extraProductsCategory","imageProcessingPending","createdAt","updatedAt"]},"ProductsCreateResponse":{"type":"object","properties":{"product":{"$ref":"#/components/schemas/ProductDto"}},"required":["product"]},"ProductsUpdateResponse":{"type":"object","properties":{"product":{"$ref":"#/components/schemas/ProductDto"}},"required":["product"]},"AppliedDefaults":{"type":"object","properties":{"language":{"type":"string","enum":["es","en","pt"]},"currency":{"type":"string"},"country":{"type":"string"},"businessType":{"type":"string"}},"required":["language","currency","country","businessType"]},"BootstrapResponse":{"type":"object","properties":{"userId":{"type":"string"},"storefrontId":{"type":["string","null"]},"userKey":{"type":"string","pattern":"^mk_user_"},"verificationStatus":{"type":"string","enum":["pending"]},"verificationExpiresAt":{"type":"string","format":"date-time"},"verificationDeliveryHint":{"type":"string","enum":["email-only"]},"appliedDefaults":{"$ref":"#/components/schemas/AppliedDefaults"},"idempotent":{"type":"boolean"},"errors":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}},"required":["type","code","message"]}}},"required":["userId","userKey","verificationStatus","verificationExpiresAt","verificationDeliveryHint","appliedDefaults"]},"VerifyResponse":{"type":"object","properties":{"userId":{"type":"string"},"verificationStatus":{"type":"string","enum":["verified"]}},"required":["userId","verificationStatus"]},"ResendResponse":{"type":"object","properties":{"verificationStatus":{"type":"string","enum":["pending"]},"verificationExpiresAt":{"type":"string","format":"date-time"}},"required":["verificationStatus","verificationExpiresAt"]},"UserDto":{"type":"object","properties":{"userId":{"type":"string"},"email":{"type":"string","format":"email"},"displayName":{"type":["string","null"]},"verificationStatus":{"type":["string","null"],"enum":["pending","verified"]},"plan":{"type":["number","null"]},"createdAt":{"type":["string","null"],"format":"date-time"},"verifiedAt":{"type":["string","null"],"format":"date-time"},"lastUserEvents":{"type":["array","null"],"items":{"type":"object","properties":{"type":{"type":"string"},"at":{"type":"string"},"reason":{"type":["string","null"]}},"required":["type","at"]}}},"required":["userId","email"]},"UserListResponse":{"type":"object","properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/UserDto"}},"nextCursor":{"type":["string","null"]}},"required":["users"]},"IssueUserKeyResponse":{"type":"object","properties":{"keyId":{"type":"string"},"rawKey":{"type":"string","pattern":"^mk_user_"},"prefix":{"type":"string"}},"required":["keyId","rawKey","prefix"]}},"parameters":{},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"mk_dev_* | mk_user_*"},"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."}}},"paths":{"/v1/me":{"get":{"summary":"Use this to confirm which user (or developer) the calling key acts as.","description":"Returns identity, plan info, and rate-limit window for the calling key. Branches on key type.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/storefronts":{"post":{"summary":"Use this when the user wants to create a new online storefront from scratch.","description":"Creates a storefront from a `StorefrontManifest`. Returns 201 with the full storefront. If the manifest contains more products than the plan allows, returns **207 Multi-Status** with the storefront created (up to plan cap) plus an `errors` array describing the over-cap items.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontCreateResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/storefronts/:storefrontId":{"patch":{"summary":"Use this when the user wants to change ANY field of an existing storefront.","description":"Partial PATCH (mutability rule §6.18.1.1). Deep-merge for nested objects, full-replace for arrays.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/storefronts/:storefrontId/publish":{"post":{"summary":"Use this when the user is ready to take their storefront live.","description":"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.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/storefronts/:storefrontId/products":{"post":{"summary":"Use this when the user wants to add a product to an existing storefront.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductsCreateResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/storefronts/:storefrontId/products/:productId":{"patch":{"summary":"Use this when the user wants to change ANY field of an existing product.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductsUpdateResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/users":{"post":{"summary":"Use this when an agent wants to create a Marea account on behalf of a user with one round-trip (account + storefront + verification email).","description":"Creates a Firebase Auth user + Firestore user doc + restricted user key + (optionally) a starter storefront via createMenuCore + sends a 6-digit verification email. Returns 201 (or 207 if the storefront manifest exceeded plan limits). The userKey is returned ONCE — store it.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BootstrapResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}},"get":{"summary":"Use this to list every user this developer key has bootstrapped (paginated 50/page).","description":"Returns users where createdByDeveloper.keyId === ctx.keyId, ordered by createdAt DESC. Use the returned `nextCursor` (createdAt ISO string) for the next page.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserListResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/users/:userId/verify":{"post":{"summary":"Use this when the user has read back the 6-digit code from their email and you want to upgrade the user-key to full scope.","description":"Validates the 6-digit code (3 attempts max), upgrades the bootstrap user-key from restricted to full scope (same key — no rotation), flips agentBootstrapped→false + verificationStatus→verified, fires the user.verified webhook stub. Cross-tenant/wrong-id → 404 leak-less.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/users/:userId/resendVerification":{"post":{"summary":"Use this when the verification email may have been lost or the code expired and you want to issue a fresh code without re-bootstrapping.","description":"Per-user rate-limited (3/hour, 5/day). Overwrites the existing apiVerificationCodes/{email} doc — old code is voided automatically. Returns the new expiry timestamp.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResendResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/users/:userId":{"get":{"summary":"Use this to poll the status of a user you previously bootstrapped (verificationStatus, plan, recent events).","description":"Returns the user DTO. Cross-developer isolation: only users that THIS developer key bootstrapped are visible — wrong-id or other-developer's-user → 404 leak-less per RFC §10.4.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDto"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/users/:userId/keys":{"post":{"summary":"Use this to issue an additional restricted user key for a verified user you previously bootstrapped (e.g. a second integration).","description":"Validates that the user was bootstrapped by THIS developer and is verified (verificationStatus===\"verified\"). Returns the raw user key once. Cross-developer attempt → 404 leak-less; pre-verify call → 422.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueUserKeyResponse"}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}},"/v1/webhooks/userEvents":{"post":{"summary":"Use this when you want to register a webhook URL to receive `user.verified` and `user.cancelled` events for users your dev key bootstraps.","description":"Registers (or revokes) a single webhook URL per developer key. Idempotent: re-POSTing overwrites; POST `{url: null}` revokes. Validation: HTTPS only, max 2048 chars, rejects loopback / metadata-server / `.internal` hostnames (basic SSRF defense; full DNS-resolution defense is TIER 2). The URL is stored at `apiKeys/{keyId}.userEventsWebhookUrl` and read by `RealWebhookService.dispatch*` at event time.","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"url":{"type":["string","null"]}},"required":["ok","url"]}}}},"400":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"409":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"410":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"413":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"429":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"500":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"503":{"description":"§9.6 error envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}}}}},"webhooks":{}}