{
  "openapi": "3.1.0",
  "info": {
    "title": "HashPay API",
    "version": "1",
    "description": "HashPay is a non-custodial stablecoin payment facilitator: USDC/USDT on eight chains, paid straight to the seller's own wallets. HashPay never holds keys or funds.\n\n**Tenancy.** An *account* owns one or more *stores*. Wallets, API keys, catalog, webhook, branding, domains and payments are store-scoped under `/v1/stores/{storeId}/…`; profile and billing are account-level.\n\n**Authentication.**\n- *Secret key* (`Authorization: Bearer sk_live_…` / `sk_test_…`): the account, store and billing surface, and checkout sessions. Any of an account's secret keys authenticates as the whole account. Plaintext keys are shown exactly once, when minted.\n- *Publishable key* (`pk_…`, in the JSON body): the buyer-facing checkout routes, together with the browser `Origin`.\n- *Capability*: payment, subscription-renewal and test-settlement routes are authorized by the unguessable id in the path.\n\n**Errors** are always `{\"error\": {\"code\": \"…\", \"message\": \"…\"}}`. Branch on `code`. Request bodies are strict: an unknown property, or malformed JSON, answers `400 bad_request`.\n\n**Money.** Prices, sessions and plan fees are integer USD cents (`unitAmountCents`, `amountCents`). On-chain amounts (`amountBaseUnits`) are strings of integer token base units (6 decimals, 18 on BSC). `amount` fields are display strings — never do math on them.\n\n**Idempotency.** Authenticated POSTs accept an `Idempotency-Key` header; see the parameter's description.\n\n**CORS** is open to every origin (no cookies; tokens only), so the API is callable from browsers directly.\n\n**Timestamps** are ISO-8601 UTC (`2026-07-13T10:04:11Z`, sometimes with fractional seconds)."
  },
  "servers": [
    {
      "url": "https://api.hashpay.dev"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "The authenticated account's profile and usage."
    },
    {
      "name": "Stores",
      "description": "Create and configure stores."
    },
    {
      "name": "Setup",
      "description": "Where a store stands on its way to live payments."
    },
    {
      "name": "Wallets",
      "description": "Receiving wallets — where buyers' money lands."
    },
    {
      "name": "Keys",
      "description": "Publishable and secret API keys."
    },
    {
      "name": "Webhooks",
      "description": "The webhook endpoint, signing secrets and delivery log."
    },
    {
      "name": "Domains",
      "description": "Per-store domain policy for live checkout."
    },
    {
      "name": "Branding",
      "description": "How the checkout widget presents the seller."
    },
    {
      "name": "Notifications",
      "description": "Email notifications to the seller."
    },
    {
      "name": "Catalog",
      "description": "Products, prices and payment links."
    },
    {
      "name": "Checkout",
      "description": "Buyer-facing checkout (publishable key) and server-created sessions (secret key)."
    },
    {
      "name": "Payments",
      "description": "Payment status, buyer actions, test settlement and history."
    },
    {
      "name": "Subscriptions",
      "description": "Recurring agreements: subscriber renewal routes and the seller's view."
    },
    {
      "name": "Billing",
      "description": "The account's own HashPay plan."
    },
    {
      "name": "Meta",
      "description": "Service health and this document."
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "Meta"
        ],
        "summary": "Liveness check",
        "security": [],
        "responses": {
          "200": {
            "description": "The service is up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok"
                      ]
                    }
                  },
                  "required": [
                    "status"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiDocument",
        "tags": [
          "Meta"
        ],
        "summary": "This OpenAPI document",
        "description": "Returns this OpenAPI 3.1 description of the public HashPay API.",
        "security": [],
        "responses": {
          "200": {
            "description": "The OpenAPI document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "An OpenAPI 3.1 document."
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkout/info": {
      "post": {
        "operationId": "getCheckoutInfo",
        "tags": [
          "Checkout"
        ],
        "summary": "Checkout display data",
        "description": "Pre-create display data for the checkout widget: the amount, seller name and branding, product, and the (network, token) options the buyer may pick. Authorized by the **publishable key in the body**; the browser `Origin` header is required and acts only as a per-store policy filter (live mode refuses domains the store rejected; test mode accepts any origin). Live keys additionally require an active account with a verified email. Counts as a sighting of the embed script for the store. Applies the same session validity rules as `POST /v1/checkout`.",
        "security": [],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The page's origin (sent by browsers automatically)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutInfoRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Display data. `acceptingPayments: false` (with `unavailableReason: \"no_wallet\"`) means the seller can't take payments in this mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutInfo"
                }
              }
            }
          },
          "400": {
            "description": "`400 origin_required` — no valid `Origin` header; `400 bad_request` — invalid JSON body (or an unknown property); not exactly one of `amount`/`priceId`/`paymentLinkId`/`sessionId`; `currency` other than `usd`; `amount` ≤ 0; metadata over its limits or using a reserved key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 missing_key` — no `publishableKey`; `401 publishable_key_required` — the key isn't a `pk_…` key; `401 invalid_key` — unknown or revoked publishable key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — live key on a suspended or banned account, or test key on a banned account; `403 email_unverified` — live key while the account owner hasn't verified their email; `403 origin_not_allowed` — live key from a domain the store rejected; `403 open_amount_disabled` — `amount` sent to a store in strict mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 price_not_found` — unknown price, a price of another store, a price whose product is inactive, or an unknown/inactive payment link; `404 session_not_found` — unknown session, or one of another store or mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 session_closed` — the session is complete or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkout": {
      "post": {
        "operationId": "createCheckout",
        "tags": [
          "Checkout"
        ],
        "summary": "Create a payment",
        "description": "The buyer picked a pair: claim a unique payment slot and return the payment to show. Authorized by the **publishable key in the body** plus a required `Origin` (same policy as `POST /v1/checkout/info`). A recurring price opens a subscription (status `INCOMPLETE`) whose first fee invoice is the returned payment (it carries `subscriptionId`), and requires `buyerEmail`. Rate-limited to 120 creations per minute per IP. In test mode a store with no wallets gets a synthetic test address; settle test payments with `POST /v1/test/payments/{id}/simulate`.",
        "security": [],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The page's origin (sent by browsers automatically)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created payment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "400": {
            "description": "`400 origin_required` — no valid `Origin` header; `400 bad_request` — invalid JSON body (or an unknown property); not exactly one of `amount`/`priceId`/`paymentLinkId`/`sessionId`; `currency` other than `usd`; `amount` ≤ 0; metadata over its limits or using a reserved key; `400 bad_request` — missing or unknown `network`/`token`; `400 unsupported_pair` — HashPay doesn't support that (network, token); `400 pair_not_allowed` — the price doesn't accept that pair; `400 price_inactive` — the price is deactivated; `400 bad_amount` — the amount converts to zero base units; `400 email_required` — recurring price without a valid `buyerEmail`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 missing_key` — no `publishableKey`; `401 publishable_key_required` — the key isn't a `pk_…` key; `401 invalid_key` — unknown or revoked publishable key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`402 volume_cap_reached` — live mode: the seller reached their plan's monthly volume ceiling.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — live key on a suspended or banned account, or test key on a banned account; `403 email_unverified` — live key while the account owner hasn't verified their email; `403 origin_not_allowed` — live key from a domain the store rejected; `403 open_amount_disabled` — `amount` sent to a store in strict mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 price_not_found` — unknown price, a price of another store, a price whose product is inactive, or an unknown/inactive payment link; `404 session_not_found` — unknown session, or one of another store or mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 session_closed` — the session is complete or expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "`422 no_wallet` — the store has no receiving wallet on that network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`429 rate_limited` — more than 120 payment creations per minute from this IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events": {
      "post": {
        "operationId": "recordWidgetEvent",
        "tags": [
          "Checkout"
        ],
        "summary": "Widget analytics beacon",
        "description": "Fire-and-forget lifecycle event from the checkout widget. Always answers `{\"ok\": true}` for a well-formed body; an unresolvable publishable key or a blank `event` is silently dropped. A resolvable key counts as a sighting of the embed script for its store.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WidgetEventRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted (or dropped).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/embed/hello": {
      "post": {
        "operationId": "embedHello",
        "tags": [
          "Checkout"
        ],
        "summary": "Embed script phone-home",
        "description": "Sent once by the embed snippet on page load so the dashboard can confirm the script is installed. Authorized by the publishable key in the body alone (no origin, email-verification or domain checks). Stamps the store's `embedSeenAt` the first time. Always answers `{\"ok\": true}` for a well-formed body, even for an unknown key.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmbedHelloRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkout/sessions": {
      "post": {
        "operationId": "createCheckoutSession",
        "tags": [
          "Checkout"
        ],
        "summary": "Create a checkout session",
        "description": "Server-side, dynamic-amount checkout (carts, variable pricing). **Requires a secret key** (`sk_…`); the key's store and mode (test/live) scope the session. The browser widget then opens it with `HashPay.checkout({ sessionId })`. Sessions live 24 hours; the first confirmed payment completes the session.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutSessionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_amount` — `amountCents` missing or ≤ 0; `400 bad_request` — metadata over its limits or using a reserved key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — a valid, active secret key (`sk_…`) is required — a dashboard token does not work here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the key's account is banned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkout/sessions/{id}": {
      "get": {
        "operationId": "getCheckoutSession",
        "tags": [
          "Checkout"
        ],
        "summary": "Get a checkout session",
        "description": "Poll a session your server minted; `status: complete` carries the winning `paymentId`. **Requires a secret key** of the session's own store and mode — any other session answers 404.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Session id (`cs_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "The session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSession"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — a valid, active secret key (`sk_…`) is required — a dashboard token does not work here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the key's account is banned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 session_not_found` — unknown session, or one of another store or mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/{id}": {
      "get": {
        "operationId": "getPayment",
        "tags": [
          "Payments"
        ],
        "summary": "Get a payment",
        "description": "Payment status for the widget's poll. **Public: the unguessable payment id is the capability** — no credential needed. For a live, still-open payment the server first runs an on-chain check (throttled to once per 12 s per payment). Optional Layer-2 re-fetch: send `Authorization: Bearer sk_…` and the read is scoped to the key's store — a payment of another store answers `404`, and an `sk_…` bearer that is unknown or revoked answers `401 invalid_key` instead of silently degrading to the public view. The body is the same either way. Non-`sk_` bearers (e.g. the dashboard's Firebase token) are ignored.",
        "security": [
          {},
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Payment id (`pay_…`) — the capability."
          }
        ],
        "responses": {
          "200": {
            "description": "The payment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "401": {
            "description": "`401 invalid_key` — an `sk_…` bearer was sent but is unknown or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 payment_not_found` — no such payment (or, with a secret key, one of another store).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`429 rate_limited` — too many requests from this IP (600/min across the public payment routes).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/{id}/cancel": {
      "post": {
        "operationId": "cancelPayment",
        "tags": [
          "Payments"
        ],
        "summary": "Cancel a payment",
        "description": "Buyer abandons the checkout. **Public: the payment id is the capability.** A `PENDING` payment becomes `CANCELED` (a live one is first re-checked on-chain, so a payment that just arrived is not canceled) and `payment.canceled` fires; any other status is returned unchanged with 200.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Payment id (`pay_…`) — the capability."
          }
        ],
        "responses": {
          "200": {
            "description": "The payment after the cancel attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "404": {
            "description": "`404 payment_not_found` — no such payment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`429 rate_limited` — too many requests from this IP (600/min across the public payment routes).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/{id}/extend": {
      "post": {
        "operationId": "extendPayment",
        "tags": [
          "Payments"
        ],
        "summary": "Extend the reservation window",
        "description": "Buyer asks for more time. **Public: the payment id is the capability.** Adds 5 minutes to `expiresAt`, capped at `createdAt` + 15 minutes. Only a `PENDING` payment whose window hasn't passed can extend.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Payment id (`pay_…`) — the capability."
          }
        ],
        "responses": {
          "200": {
            "description": "The payment with its new `expiresAt`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "404": {
            "description": "`404 payment_not_found` — no such payment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 not_extendable` — the payment isn't `PENDING` or its window already passed; `409 extend_cap_reached` — already at `createdAt` + 15 minutes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/test/payments/{id}/simulate": {
      "post": {
        "operationId": "simulateTestPayment",
        "tags": [
          "Payments"
        ],
        "summary": "Settle a test payment",
        "description": "Drive a **test-mode** payment to `CONFIRMED` without any chain activity and fire the real `payment.confirmed` webhook (with `data.mode: \"test\"`). **Public: the payment id is the capability**; live payments are refused, and test payments move no money and count against no quota. Idempotent: an already-`CONFIRMED` payment is returned as-is. A simulated subscription fee activates the subscription immediately.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Payment id (`pay_…`) — the capability."
          }
        ],
        "responses": {
          "200": {
            "description": "The confirmed payment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "400": {
            "description": "`400 not_test_mode` — the payment is live.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 payment_not_found` — no such payment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 not_open` — the payment is expired, canceled, underpaid or overpaid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`429 rate_limited` — too many requests from this IP (600/min across the public payment routes).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "Account"
        ],
        "summary": "Get the authenticated account",
        "description": "The authenticated account: profile, status, email verification, tier and month-to-date usage, and the supported pairs. A 200 here proves the credential works. Any of the account's secret keys authenticates as the whole account.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountSummary"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/account": {
      "get": {
        "operationId": "getAccount",
        "tags": [
          "Account"
        ],
        "summary": "Get the authenticated account (alias of /v1/me)",
        "description": "The authenticated account: profile, status, email verification, tier and month-to-date usage, and the supported pairs. A 200 here proves the credential works. Any of the account's secret keys authenticates as the whole account.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountSummary"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateAccount",
        "tags": [
          "Account"
        ],
        "summary": "Replace the account profile",
        "description": "Writes `businessName`, `supportEmail`, `country` and `website` together — **an omitted field is cleared to `null`**, so send the complete profile. `securityEmail` can't be changed here.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountSummary"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/billing/plans": {
      "get": {
        "operationId": "listPlans",
        "tags": [
          "Billing"
        ],
        "summary": "List HashPay plans",
        "description": "Public plan catalog: each tier's monthly volume ceiling and monthly/yearly fee. No credential needed.",
        "security": [],
        "responses": {
          "200": {
            "description": "The plans.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "plans": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Plan"
                      },
                      "description": "In order: free, starter, pro, enterprise."
                    }
                  },
                  "required": [
                    "plans"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/billing/usage": {
      "get": {
        "operationId": "getUsage",
        "tags": [
          "Billing"
        ],
        "summary": "Get plan usage",
        "description": "Effective tier, month-to-date received volume vs. its ceiling, transaction count, paid-through date and the current plan subscription.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/billing/subscription": {
      "get": {
        "operationId": "getBillingSubscription",
        "tags": [
          "Billing"
        ],
        "summary": "Get the account's plan subscription",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The subscription, or null.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "subscription": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Subscription"
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "`null` when the account has no plan subscription."
                    }
                  },
                  "required": [
                    "subscription"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/billing/subscribe": {
      "post": {
        "operationId": "subscribe",
        "tags": [
          "Billing"
        ],
        "summary": "Subscribe to or upgrade a plan",
        "description": "Returns the **fee payment** to pay; the tier applies when it confirms (HashPay is non-custodial for its own fees too — send exactly `amountBaseUnits` to `payTo`, or open it in the widget). From Free this charges the full fee and starts a new anniversary. From a paid tier to a higher one it charges only the fee difference and keeps the anniversary and interval. Re-posting the same tier and interval while the first fee is still unpaid returns that same payment with 200; a different choice cancels the stale pending subscription and starts a new one (201).",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscribeRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A new fee payment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingPayment"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "200": {
            "description": "The still-open fee payment of the same pending subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingPayment"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `tier`, `network` or `token` missing, or an unknown tier, interval, network or token; `400 bad_tier` — `free` or `enterprise` requested — only `starter` and `pro` are self-serve; `400 unsupported_pair` — HashPay doesn't support that (network, token); `400 interval_change_unsupported` — an upgrade asked for a different interval than the current one; `400 not_an_upgrade` — the target tier doesn't cost more than the current one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "`500 subscribe_failed` — the subscription could not be started.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "`503 billing_unavailable` — HashPay's fee-receiving store has no wallet on that network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/billing/subscription/cancel": {
      "post": {
        "operationId": "cancelBillingSubscription",
        "tags": [
          "Billing"
        ],
        "summary": "Cancel the account's plan subscription",
        "description": "Stops renewal. The paid period runs to its end, then the account reverts to Free.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Canceled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "canceled": {
                      "type": "string",
                      "description": "The canceled subscription's id."
                    },
                    "note": {
                      "type": "string",
                      "description": "Human-readable note about what happens next."
                    }
                  },
                  "required": [
                    "canceled",
                    "note"
                  ]
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_idempotency_key` — malformed `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 no_subscription` — no plan subscription to cancel.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/subscriptions/{id}/renewal": {
      "get": {
        "operationId": "getSubscriptionRenewal",
        "tags": [
          "Subscriptions"
        ],
        "summary": "Renewal page data",
        "description": "Data for the hosted renewal page. **Public: the unguessable subscription id (from the renewal email link) is the capability.**",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Subscription id — the capability carried by the renewal link."
          }
        ],
        "responses": {
          "200": {
            "description": "Renewal data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenewalInfo"
                }
              }
            }
          },
          "404": {
            "description": "`404 subscription_not_found` — no such subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/subscriptions/{id}/renew": {
      "post": {
        "operationId": "renewSubscription",
        "tags": [
          "Subscriptions"
        ],
        "summary": "Start a renewal payment",
        "description": "Claim the next cycle's fee invoice and return it as a payment for the widget. **Public: the subscription id is the capability.** Refresh-safe: while the cycle already has an open, unexpired invoice, that same payment is returned (200) instead of a new one. A `CANCELED` subscription can be restored this way.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Subscription id — the capability carried by the renewal link."
          }
        ],
        "responses": {
          "201": {
            "description": "A new fee invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "200": {
            "description": "The cycle's existing open invoice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payment"
                }
              }
            }
          },
          "404": {
            "description": "`404 subscription_not_found` — no such subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 not_renewable` — the subscription is `INCOMPLETE` (never paid).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/subscriptions/{id}/cancel": {
      "post": {
        "operationId": "cancelSubscription",
        "tags": [
          "Subscriptions"
        ],
        "summary": "Cancel a subscription (subscriber)",
        "description": "Buyer-initiated cancel. **Public: the subscription id is the capability** — stopping reminders must not require an account. Stops renewal reminders; the paid period runs to its end. Idempotent: an already-canceled subscription answers 200 without `note`.",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Subscription id — the capability carried by the renewal link."
          }
        ],
        "responses": {
          "200": {
            "description": "Canceled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "canceled": {
                      "type": "string",
                      "description": "The subscription id."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "CANCELED"
                      ]
                    },
                    "note": {
                      "type": "string",
                      "description": "Present only when this call did the canceling."
                    }
                  },
                  "required": [
                    "canceled",
                    "status"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "`404 subscription_not_found` — no such subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores": {
      "get": {
        "operationId": "listStores",
        "tags": [
          "Stores"
        ],
        "summary": "List stores",
        "description": "All of the account's stores, newest first.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The stores.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "stores": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/StoreSummary"
                      }
                    }
                  },
                  "required": [
                    "stores"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createStore",
        "tags": [
          "Stores"
        ],
        "summary": "Create a store",
        "description": "Creates the store and mints its four API keys (publishable/secret × test/live) — **without returning their plaintext**: mint a key with `POST /v1/stores/{storeId}/keys` to get a usable one.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `name` missing or blank.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}": {
      "get": {
        "operationId": "getStore",
        "tags": [
          "Stores"
        ],
        "summary": "Get a store",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateStore",
        "tags": [
          "Stores"
        ],
        "summary": "Update a store",
        "description": "Partial update of `name` and `openAmountDisabled` (strict mode). Omitted fields are unchanged.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/setup": {
      "get": {
        "operationId": "getStoreSetup",
        "tags": [
          "Setup"
        ],
        "summary": "Get the store's setup checklist",
        "description": "Setup checklist: what this store still needs before it can take live payments, and whether the integration has proven itself end to end. Designed for agents and scripts to resume or verify a setup.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The checklist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SetupChecklist"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/wallets": {
      "get": {
        "operationId": "listWallets",
        "tags": [
          "Wallets"
        ],
        "summary": "List receiving wallets",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The wallets.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "wallets": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Wallet"
                      }
                    }
                  },
                  "required": [
                    "wallets"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "addWallet",
        "tags": [
          "Wallets"
        ],
        "summary": "Add a receiving wallet",
        "description": "Adds one address on one network (`network`) or on several at once (`networks` — e.g. one ordinary EVM wallet on several EVM chains). All-or-nothing: every network is validated and duplicate-checked before anything is saved. Payments go straight to this address and a wrong one loses every payment quoted on it, irreversibly — take the address verbatim from the seller. Emails a security notice to `securityEmail`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WalletAddRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The store with its new wallet(s).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `address` missing, or not exactly one of `network` | `networks`; `400 unsupported` — an unknown network id; `400 bad_address` — the address fails validation for that network; `message` states the precise reason (chain format, EIP-55 checksum on mixed-case EVM input, Tron base58check checksum, zero/burn address, Solana program id, or a USDC/USDT token contract or mint pasted instead of a wallet) and is safe to show as-is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running; `409 duplicate_address` — the address is already a wallet on this store for that network (for `networks`, any one of them).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteWallet",
        "tags": [
          "Wallets"
        ],
        "summary": "Remove a receiving wallet",
        "description": "Removes the wallet matching `network` + `address` (query parameters, not a body). Lenient on purpose: no address validation, so a pre-validation junk address stays removable; a non-matching address is a no-op 200. Emails a security notice when a wallet was removed.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "network",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Network"
            },
            "description": "Network id (case-insensitive)."
          },
          {
            "name": "address",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The address as listed (EVM matching is case-insensitive; Tron accepts base58 or hex)."
          }
        ],
        "responses": {
          "200": {
            "description": "The store after removal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — `network` or `address` missing; `400 unsupported` — unknown network id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/wallets/copy": {
      "post": {
        "operationId": "copyWallets",
        "tags": [
          "Wallets"
        ],
        "summary": "Copy wallets from another store",
        "description": "Merges another of the account's stores' wallets into this one (deduplicated by network + address). Emails a security notice when anything was added.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WalletCopyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The store with the merged wallets.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `fromStoreId` missing; `400 bad_address` — the source store holds an address saved before validation existed — remove it there first; `message` names it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 store_not_found` — the source store doesn't exist or belongs to another account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/keys": {
      "get": {
        "operationId": "listKeys",
        "tags": [
          "Keys"
        ],
        "summary": "List active API keys",
        "description": "Active keys only. Publishable keys are listed in full; secret keys are masked.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The keys.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiKey"
                      }
                    }
                  },
                  "required": [
                    "keys"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createKey",
        "tags": [
          "Keys"
        ],
        "summary": "Mint an API key",
        "description": "Mints a key and returns its **plaintext once**. Emails a security notice to `securityEmail`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KeyCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new key (plaintext shown once).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MintedKey"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — unknown `mode`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/keys/{keyId}": {
      "delete": {
        "operationId": "revokeKey",
        "tags": [
          "Keys"
        ],
        "summary": "Revoke an API key",
        "description": "Revokes immediately. Don't revoke the key you authenticate with before capturing a replacement. Emails a security notice to `securityEmail`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Key id (`key_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Revoked"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 key_not_found` — no such key on this store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/webhook": {
      "put": {
        "operationId": "setWebhookEndpoint",
        "tags": [
          "Webhooks"
        ],
        "summary": "Register the webhook endpoint",
        "description": "Sets (or replaces) the store's single webhook endpoint. The URL is SSRF-guarded: it must be `https://`, include a host, not embed credentials, and not resolve to a loopback, link-local, private, multicast or unique-local address (re-checked at every delivery) — `localhost` won't register; use a tunnel for local development. If the store has no active signing secret yet, one is minted and returned once as `webhookSecret` with its `secretId`. Emails a security notice when the URL changes or a secret is minted.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUrlRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The registered endpoint (plus the first signing secret, once).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpoint"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_request` — `url` missing or blank; `400 invalid_url` — the URL is rejected; `message` says why (not a valid URL, not https, no host, embedded credentials, or an internal address).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/webhook/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "tags": [
          "Webhooks"
        ],
        "summary": "Webhook delivery log",
        "description": "Recent outbox rows for this store, newest first: each event's status, attempt count, what your server answered (status and body), the next retry and the exact payload. Filters apply before the limit.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "delivered",
                "dead",
                "no_endpoint",
                "all"
              ]
            },
            "description": "Only rows in this status (case-insensitive); `all` or omitted = every status."
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/EventType"
            },
            "description": "Only this event type (exact match)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Rows to return, clamped to 1–200; default 50 (a non-number falls back to 50)."
          }
        ],
        "responses": {
          "200": {
            "description": "The delivery log.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    },
                    "endpoint": {
                      "type": "string",
                      "description": "The store's current webhook URL, or an empty string when none is registered."
                    }
                  },
                  "required": [
                    "deliveries",
                    "endpoint"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — unknown `status`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/webhook/secrets": {
      "get": {
        "operationId": "listWebhookSecrets",
        "tags": [
          "Webhooks"
        ],
        "summary": "List active signing secrets",
        "description": "Active secrets only, newest first, masked. Each delivery is signed with every active secret.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The secrets.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secrets": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookSecret"
                      }
                    }
                  },
                  "required": [
                    "secrets"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createWebhookSecret",
        "tags": [
          "Webhooks"
        ],
        "summary": "Mint a signing secret",
        "description": "Mints a signing secret and returns its plaintext once. At most **2 active** per store (one current + one rotation overlap): mint the new one, deploy it, then revoke the old. No request body. Emails a security notice to `securityEmail`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "201": {
            "description": "The new secret (plaintext shown once).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSecretCreated"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_idempotency_key` — malformed `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running; `409 too_many_secrets` — 2 secrets are already active — revoke one first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/webhook/secrets/{secretId}": {
      "delete": {
        "operationId": "revokeWebhookSecret",
        "tags": [
          "Webhooks"
        ],
        "summary": "Revoke a signing secret",
        "description": "Emails a security notice to `securityEmail`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "secretId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Secret id (`whs_…`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Revoked"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 secret_not_found` — no such secret on this store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/branding": {
      "put": {
        "operationId": "setBranding",
        "tags": [
          "Branding"
        ],
        "summary": "Set checkout branding",
        "description": "`displayName`, `logoUrl` and `color` are replaced together: an omitted one is cleared.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrandingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/notifications": {
      "put": {
        "operationId": "setNotifications",
        "tags": [
          "Notifications"
        ],
        "summary": "Set email notifications",
        "description": "Which events email a human, and where. Partial update — an omitted field keeps its stored value.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_request` — `email` isn't a plausible address, or an unknown event in `events`; `400 no_recipient` — enabling with no override email while the account has no `supportEmail`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/notifications/test": {
      "post": {
        "operationId": "sendTestNotification",
        "tags": [
          "Notifications"
        ],
        "summary": "Send a test email",
        "description": "Sends a sample `payment.confirmed` email to the address the settings currently resolve to, whether or not notifications are enabled, and reports whether the mail provider accepted it. No request body.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Accepted by the mail provider.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sent": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "email": {
                      "type": "string",
                      "description": "Where it was sent."
                    }
                  },
                  "required": [
                    "sent",
                    "email"
                  ]
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 no_recipient` — no override email and no account `supportEmail`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "`502 email_send_failed` — the mail provider refused the email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/domains": {
      "get": {
        "operationId": "listDomains",
        "tags": [
          "Domains"
        ],
        "summary": "List domain policy entries",
        "description": "Domains are a blacklist-only policy on live checkout: unknown origins transact and are surfaced as `PENDING` after a confirmed payment; only `REJECTED` blocks.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The domains.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domains": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Domain"
                      }
                    }
                  },
                  "required": [
                    "domains"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "addDomain",
        "tags": [
          "Domains"
        ],
        "summary": "Add a domain (whitelist)",
        "description": "Domains are a blacklist-only policy on live checkout: unknown origins transact and are surfaced as `PENDING` after a confirmed payment; only `REJECTED` blocks. An explicit add is `APPROVED`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DomainRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The store with the new domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `domain` missing or blank.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running; `409 duplicate_domain` — the domain already has an entry (any status).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteDomain",
        "tags": [
          "Domains"
        ],
        "summary": "Remove a domain entry",
        "description": "Removes the entry for `domain` (a hostname or URL). A missing or unknown domain is a no-op 200.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "domain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Hostname or URL to remove."
          }
        ],
        "responses": {
          "200": {
            "description": "The store after removal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/domains/accept": {
      "post": {
        "operationId": "acceptDomain",
        "tags": [
          "Domains"
        ],
        "summary": "Accept a domain",
        "description": "Domains are a blacklist-only policy on live checkout: unknown origins transact and are surfaced as `PENDING` after a confirmed payment; only `REJECTED` blocks. Sets the domain to `APPROVED`, adding it if absent.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DomainRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `domain` missing or blank.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/domains/reject": {
      "post": {
        "operationId": "rejectDomain",
        "tags": [
          "Domains"
        ],
        "summary": "Reject (block) a domain",
        "description": "Domains are a blacklist-only policy on live checkout: unknown origins transact and are surfaced as `PENDING` after a confirmed payment; only `REJECTED` blocks. Sets the domain to `REJECTED`, adding it if absent; live checkout from it then answers `403 origin_not_allowed`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DomainRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `domain` missing or blank.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/products": {
      "get": {
        "operationId": "listProducts",
        "tags": [
          "Catalog"
        ],
        "summary": "List products",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "products": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    }
                  },
                  "required": [
                    "products"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createProduct",
        "tags": [
          "Catalog"
        ],
        "summary": "Create a product",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new (active) product.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `name` missing or blank.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/products/{productId}": {
      "put": {
        "operationId": "updateProduct",
        "tags": [
          "Catalog"
        ],
        "summary": "Update a product",
        "description": "Partial update. Deactivating takes all of the product's prices off sale.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "productId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Product id (`prod_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated product.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 product_not_found` — no such product on this store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/prices": {
      "get": {
        "operationId": "listPrices",
        "tags": [
          "Catalog"
        ],
        "summary": "List prices",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The prices.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "prices": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Price"
                      }
                    }
                  },
                  "required": [
                    "prices"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPrice",
        "tags": [
          "Catalog"
        ],
        "summary": "Create a price",
        "description": "A price is immutable except `active`: to change an amount, create a new price and deactivate the old one. A `recurring` price makes checkout open a subscription (buyer email required; HashPay emails reminders and a renew link before each anniversary — never an auto-charge).",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PriceCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new (active) price.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Price"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `productId` missing or `unitAmountCents` ≤ 0; `type` not `one_time`/`recurring`; unknown `interval`; or `interval` on a one-time price.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 product_not_found` — no such product on this store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/prices/{priceId}": {
      "put": {
        "operationId": "updatePrice",
        "tags": [
          "Catalog"
        ],
        "summary": "Activate or deactivate a price",
        "description": "Only `active` can change. Deactivation stops new checkouts immediately (`400 price_inactive`); in-flight payments settle unaffected.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "priceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Price id (`price_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PriceUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated price.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Price"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_request` — `active` missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 price_not_found` — no such price on this store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/payment_links": {
      "get": {
        "operationId": "listPaymentLinks",
        "tags": [
          "Catalog"
        ],
        "summary": "List payment links",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The payment links.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "paymentLinks": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PaymentLink"
                      }
                    }
                  },
                  "required": [
                    "paymentLinks"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPaymentLink",
        "tags": [
          "Catalog"
        ],
        "summary": "Create a payment link",
        "description": "A shareable hosted checkout for one price.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentLinkCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new (active) link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLink"
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property; `400 bad_idempotency_key` — malformed `Idempotency-Key`; `400 bad_request` — `priceId` missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 price_not_found` — no such price on this store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/payment_links/{linkId}": {
      "put": {
        "operationId": "updatePaymentLink",
        "tags": [
          "Catalog"
        ],
        "summary": "Update a payment link",
        "description": "Partial update. Deactivating kills the shared link without deleting its history.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "linkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Payment link id (`plink_…`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentLinkUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLink"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_request` — invalid JSON body — malformed, wrong types, or an unknown property.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 link_not_found` — no such payment link on this store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/payments": {
      "get": {
        "operationId": "listPayments",
        "tags": [
          "Payments"
        ],
        "summary": "List the store's payments",
        "description": "Payment history, newest first, paginated: pass the response's `nextCursor` as `startAfter`.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/Mode"
            },
            "description": "Only this mode (exact, lowercase)."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/PaymentStatus"
            },
            "description": "Only this status (case-insensitive)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "description": "Page size, clamped to 1–500; default 100."
          },
          {
            "name": "startAfter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The `nextCursor` of the previous page (a payment id)."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of payments.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentList"
                }
              }
            }
          },
          "400": {
            "description": "`400 bad_status` — unknown `status`; `400 bad_request` — `limit` is not a number; `400 bad_cursor` — `startAfter` isn't in the result set under these filters — restart from the first page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/subscriptions": {
      "get": {
        "operationId": "listStoreSubscriptions",
        "tags": [
          "Subscriptions"
        ],
        "summary": "List the store's subscriptions",
        "description": "Subscriptions to the store's recurring prices, newest first.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          }
        ],
        "responses": {
          "200": {
            "description": "The subscriptions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "subscriptions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Subscription"
                      }
                    }
                  },
                  "required": [
                    "subscriptions"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stores/{storeId}/subscriptions/{id}/cancel": {
      "post": {
        "operationId": "cancelStoreSubscription",
        "tags": [
          "Subscriptions"
        ],
        "summary": "Cancel a subscription (seller)",
        "description": "Seller-initiated cancel of one of the store's subscriptions. Idempotent.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/StoreId"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Subscription id."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Canceled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "canceled": {
                      "type": "string",
                      "description": "The subscription id."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "CANCELED"
                      ]
                    }
                  },
                  "required": [
                    "canceled",
                    "status"
                  ]
                }
              }
            },
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/IdempotentReplayed"
              }
            }
          },
          "400": {
            "description": "`400 bad_idempotency_key` — malformed `Idempotency-Key`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`401 unauthorized` — no usable credential: a `sk_…` bearer that is unknown or revoked, or a dashboard token that can't be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`403 account_disabled` — the account is banned (secret-key auth).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`404 account_not_found` — the dashboard token verified but maps to no account; `404 store_not_found` — the store doesn't exist or belongs to another account (existence is never leaked); `404 subscription_not_found` — no such subscription on this store.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`409 idempotency_key_reused` — the key was already used with a different method, path or body; `409 idempotency_in_progress` — the original request with this key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A secret key (`sk_live_…` / `sk_test_…`) from the dashboard's Integration page. Any of an account's secret keys authenticates as the whole account. (The dashboard itself sends a Firebase ID token here.)"
      }
    },
    "parameters": {
      "StoreId": {
        "name": "storeId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Store id (`store_…`). Must belong to the authenticated account."
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        },
        "description": "Optional. 1–255 characters, unique per logical operation (a UUID is ideal). Retrying a POST with the same key within 24 hours returns the original response (status and body) instead of repeating the operation, with the response header `Idempotent-Replayed: true`. Keys are scoped to the account. Reusing a key with a different method, path or body answers `409 idempotency_key_reused`; retrying while the original request is still running answers `409 idempotency_in_progress`; a malformed key answers `400 bad_idempotency_key`. Responses with status 5xx are not stored, so a retry after a server error re-executes."
      }
    },
    "headers": {
      "IdempotentReplayed": {
        "description": "`true` when this response is a stored replay of an earlier request with the same `Idempotency-Key`; absent otherwise.",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ]
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable, machine-readable error code (snake_case). Branch on this."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation. Where documented as precise (e.g. `bad_address`), safe to show as-is."
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ],
        "description": "Every non-2xx response carries this envelope."
      },
      "Network": {
        "type": "string",
        "enum": [
          "ethereum",
          "polygon",
          "avalanche",
          "bsc",
          "arbitrum",
          "base",
          "tron",
          "solana"
        ],
        "description": "Chain id. The six EVM chains share one address format; `tron` and `solana` each have their own."
      },
      "Token": {
        "type": "string",
        "enum": [
          "usdc",
          "usdt"
        ],
        "description": "Stablecoin id. Not every (network, token) pair exists — see `supportedPairs` on `GET /v1/me` (there is no `tron`/`usdc`)."
      },
      "Mode": {
        "type": "string",
        "enum": [
          "test",
          "live"
        ],
        "description": "Test vs. live partition. Every key, session, payment and subscription carries one."
      },
      "KeyKind": {
        "type": "string",
        "enum": [
          "publishable",
          "secret"
        ],
        "description": "`publishable` (`pk_…`, safe in browsers) or `secret` (`sk_…`, server-side only)."
      },
      "PaymentStatus": {
        "type": "string",
        "enum": [
          "PENDING",
          "DETECTED",
          "CONFIRMED",
          "EXPIRED",
          "UNDERPAID",
          "OVERPAID",
          "CANCELED"
        ],
        "description": "Payment lifecycle. Happy path `PENDING → DETECTED → CONFIRMED`; a reorg can send `DETECTED` back to `PENDING`. `EXPIRED`, `UNDERPAID`, `OVERPAID` and `CANCELED` are terminal side exits. Only `CONFIRMED` is settled money."
      },
      "SubscriptionStatus": {
        "type": "string",
        "enum": [
          "INCOMPLETE",
          "ACTIVE",
          "PAST_DUE",
          "CANCELED"
        ],
        "description": "`INCOMPLETE` until the first cycle's fee confirms; `ACTIVE` once a cycle is paid; `PAST_DUE` once the anniversary passes unpaid; `CANCELED` after cancellation or once the grace period elapses unpaid."
      },
      "AccountStatus": {
        "type": "string",
        "enum": [
          "ACTIVE",
          "SUSPENDED",
          "BANNED"
        ],
        "description": "`SUSPENDED` is the reversible kill switch (live checkout goes inert); `BANNED` is permanent."
      },
      "DomainStatus": {
        "type": "string",
        "enum": [
          "PENDING",
          "APPROVED",
          "REJECTED"
        ],
        "description": "Blacklist-only domain policy: `PENDING` = observed (surfaced after a confirmed payment, awaiting review), `APPROVED` = whitelisted, `REJECTED` = blacklisted (live checkout from it is refused)."
      },
      "PlanTier": {
        "type": "string",
        "enum": [
          "free",
          "starter",
          "pro",
          "enterprise"
        ],
        "description": "HashPay billing tier. `starter` and `pro` are self-serve; `enterprise` is assigned by HashPay."
      },
      "Interval": {
        "type": "string",
        "enum": [
          "month",
          "year"
        ],
        "description": "Billing interval of a recurring price or subscription."
      },
      "PriceType": {
        "type": "string",
        "enum": [
          "one_time",
          "recurring"
        ],
        "description": "A `recurring` price starts a subscription at checkout."
      },
      "WebhookDeliveryStatus": {
        "type": "string",
        "enum": [
          "pending",
          "delivered",
          "dead",
          "no_endpoint"
        ],
        "description": "`pending` = queued or retrying; `delivered` = acknowledged with a 2xx; `dead` = retries exhausted (72h); `no_endpoint` = the store had no webhook URL when the event fired."
      },
      "EventType": {
        "type": "string",
        "enum": [
          "payment.confirmed",
          "payment.detected",
          "payment.underpaid",
          "payment.overpaid",
          "payment.expired",
          "payment.canceled",
          "subscription.created",
          "subscription.activated",
          "subscription.renewed",
          "subscription.upgraded",
          "subscription.past_due",
          "subscription.expired",
          "subscription.canceled",
          "subscription.reminder"
        ],
        "description": "An event HashPay emits (webhooks and email notifications)."
      },
      "SetupStepId": {
        "type": "string",
        "enum": [
          "email_verified",
          "wallets",
          "webhook_endpoint",
          "test_payment",
          "webhook_verified",
          "embed_installed"
        ],
        "description": "A setup checklist step id."
      },
      "Metadata": {
        "type": "object",
        "additionalProperties": {
          "type": "string"
        },
        "maxProperties": 20,
        "description": "Your own correlation data (e.g. `{\"orderId\":\"1234\"}`): string values, at most 20 keys and 2048 characters of keys+values in total. The keys `subscriptionId`, `purpose`, `subscriberAccountId`, `tier` and `sessionId` are reserved by HashPay and rejected (`400 bad_request`). Echoed on webhooks."
      },
      "DisplayAmount": {
        "type": "string",
        "pattern": "^[0-9]+(\\.[0-9]+)?$",
        "examples": [
          "19.99"
        ],
        "description": "Human-readable decimal amount in USD/token units with trailing zeros stripped (e.g. `\"19.99\"`, `\"49\"`, `\"19.9\"`). For display only — never do money math on it."
      },
      "BaseUnits": {
        "type": "string",
        "pattern": "^[0-9]+$",
        "examples": [
          "19990000"
        ],
        "description": "Exact on-chain amount as a string of integer token base units (6 decimals everywhere except BSC, where USDC/USDT have 18). Send exactly this."
      },
      "Branding": {
        "type": "object",
        "properties": {
          "displayName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Name shown to the buyer instead of the store name."
          },
          "logoUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Logo shown in the checkout widget."
          },
          "color": {
            "type": [
              "string",
              "null"
            ],
            "description": "Accent color, e.g. `#251160`."
          }
        },
        "required": [
          "displayName",
          "logoUrl",
          "color"
        ],
        "description": "Checkout branding."
      },
      "Notifications": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether event emails are sent at all."
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "The store's recipient override. `null` means \"the account's `supportEmail`\".",
            "format": "email"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventType"
            },
            "description": "Events that send an email when `enabled`."
          },
          "availableEvents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventType"
            },
            "description": "Every event that can be selected, in display order."
          }
        },
        "required": [
          "enabled",
          "email",
          "events",
          "availableEvents"
        ],
        "description": "Per-store email notification settings (to humans; the webhook is for servers)."
      },
      "Wallet": {
        "type": "object",
        "properties": {
          "network": {
            "$ref": "#/components/schemas/Network"
          },
          "address": {
            "type": "string",
            "description": "Receiving address in display form: lowercase `0x…` hex on EVM chains, base58 `T…` on Tron, base58 on Solana."
          },
          "label": {
            "type": "string",
            "description": "Free-form label (empty string when none was given)."
          }
        },
        "required": [
          "network",
          "address",
          "label"
        ],
        "description": "A receiving wallet. Payments go straight to this address — HashPay never holds funds."
      },
      "Domain": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "description": "Lowercased hostname, e.g. `shop.example.com`."
          },
          "status": {
            "$ref": "#/components/schemas/DomainStatus"
          }
        },
        "required": [
          "domain",
          "status"
        ]
      },
      "StoreSummary": {
        "type": "object",
        "properties": {
          "storeId": {
            "type": "string",
            "description": "Store id (`store_…`)."
          },
          "name": {
            "type": "string",
            "description": "Store name."
          },
          "wallets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Wallet"
            }
          },
          "domains": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Domain"
            }
          },
          "branding": {
            "$ref": "#/components/schemas/Branding"
          },
          "notifications": {
            "$ref": "#/components/schemas/Notifications"
          },
          "webhookUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "The store's webhook endpoint, or `null` when none is registered.",
            "format": "uri"
          },
          "hasWebhookSecret": {
            "type": "boolean",
            "description": "Whether at least one webhook signing secret is active."
          },
          "openAmountDisabled": {
            "type": "boolean",
            "description": "Strict mode: when `true` the public checkout refuses browser-supplied amounts and accepts only price, payment-link and session references."
          },
          "scriptSeen": {
            "type": "boolean",
            "description": "Whether the embed script carrying one of this store's publishable keys has ever run on a page."
          },
          "embedSeenAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the embed script was first seen running (write-once), or `null`."
          }
        },
        "required": [
          "storeId",
          "name",
          "wallets",
          "domains",
          "branding",
          "notifications",
          "webhookUrl",
          "hasWebhookSecret",
          "openAmountDisabled",
          "scriptSeen",
          "embedSeenAt"
        ],
        "description": "A store and its configuration. Returned by most store mutations."
      },
      "SupportedPair": {
        "type": "object",
        "properties": {
          "network": {
            "$ref": "#/components/schemas/Network"
          },
          "token": {
            "$ref": "#/components/schemas/Token"
          },
          "decimals": {
            "type": "integer",
            "format": "int32",
            "description": "Token decimals on this network (18 on BSC, 6 elsewhere)."
          }
        },
        "required": [
          "network",
          "token",
          "decimals"
        ],
        "description": "A (network, token) pair HashPay supports."
      },
      "AccountUsage": {
        "type": "object",
        "properties": {
          "tier": {
            "$ref": "#/components/schemas/PlanTier"
          },
          "monthlyVolumeCents": {
            "type": "integer",
            "format": "int64",
            "description": "USD cents received this calendar month (UTC) across all the account's stores."
          },
          "ceilingCents": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Monthly volume ceiling of `tier` in USD cents; `null` when unbounded."
          },
          "txCount": {
            "type": "integer",
            "format": "int32",
            "description": "Confirmed live transactions counted (information only; gates nothing)."
          },
          "paidPeriodEnd": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the paid tier runs out, or `null` (free/enterprise)."
          }
        },
        "required": [
          "tier",
          "monthlyVolumeCents",
          "ceilingCents",
          "txCount",
          "paidPeriodEnd"
        ]
      },
      "AccountSummary": {
        "type": "object",
        "properties": {
          "accountId": {
            "type": "string",
            "description": "Account id (`acct_…`)."
          },
          "businessName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Business name."
          },
          "supportEmail": {
            "type": [
              "string",
              "null"
            ],
            "description": "Support email (editable with a secret key)."
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "Country code."
          },
          "website": {
            "type": [
              "string",
              "null"
            ],
            "description": "Website."
          },
          "status": {
            "$ref": "#/components/schemas/AccountStatus"
          },
          "emailVerified": {
            "type": "boolean",
            "description": "Whether the owner verified their email. Live checkout answers `403 email_unverified` until they do — only a human can click the link."
          },
          "securityEmail": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where security notices go: the sign-in address (falls back to `supportEmail` until the owner next signs in). No API key can change it."
          },
          "tier": {
            "$ref": "#/components/schemas/PlanTier"
          },
          "usage": {
            "$ref": "#/components/schemas/AccountUsage",
            "description": "Account-level volume metering (one pool for all stores)."
          },
          "supportedPairs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupportedPair"
            },
            "description": "Every (network, token) pair HashPay supports."
          }
        },
        "required": [
          "accountId",
          "businessName",
          "supportEmail",
          "country",
          "website",
          "status",
          "emailVerified",
          "securityEmail",
          "tier",
          "usage",
          "supportedPairs"
        ],
        "description": "The authenticated account."
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "keyId": {
            "type": "string",
            "description": "Key id (`key_…`)."
          },
          "kind": {
            "$ref": "#/components/schemas/KeyKind"
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "display": {
            "type": "string",
            "description": "The full key for publishable keys; a masked preview (`sk_live_••••wxyz`) for secret keys."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the key was minted."
          }
        },
        "required": [
          "keyId",
          "kind",
          "mode",
          "display",
          "createdAt"
        ],
        "description": "An active API key (listing form — never the secret plaintext)."
      },
      "MintedKey": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The full plaintext key (`pk_test_…`, `pk_live_…`, `sk_test_…`, `sk_live_…`). Shown exactly once — capture it now."
          },
          "kind": {
            "$ref": "#/components/schemas/KeyKind"
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          }
        },
        "required": [
          "key",
          "kind",
          "mode"
        ],
        "description": "A newly minted key. The response carries no `keyId`; list the keys to find it."
      },
      "WebhookSecret": {
        "type": "object",
        "properties": {
          "secretId": {
            "type": "string",
            "description": "Secret id (`whs_…`)."
          },
          "display": {
            "type": "string",
            "description": "Masked preview, e.g. `whsec_••••wxyz`."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the secret was minted."
          }
        },
        "required": [
          "secretId",
          "display",
          "createdAt"
        ],
        "description": "An active webhook signing secret (masked)."
      },
      "WebhookSecretCreated": {
        "type": "object",
        "properties": {
          "secretId": {
            "type": "string",
            "description": "Secret id (`whs_…`)."
          },
          "secret": {
            "type": "string",
            "description": "The plaintext signing secret (`whsec_…`). Shown exactly once."
          },
          "display": {
            "type": "string",
            "description": "Masked preview, e.g. `whsec_••••wxyz`."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the secret was minted."
          }
        },
        "required": [
          "secretId",
          "secret",
          "display",
          "createdAt"
        ]
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "webhookUrl": {
            "type": "string",
            "description": "The registered endpoint.",
            "format": "uri"
          },
          "secretId": {
            "type": "string",
            "description": "Present only when this call minted the store's first active signing secret."
          },
          "webhookSecret": {
            "type": "string",
            "description": "Present only alongside `secretId`: the plaintext signing secret (`whsec_…`), shown exactly once."
          }
        },
        "required": [
          "webhookUrl"
        ]
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The event id (e.g. `pay_…:payment.confirmed`) — also the `X-HashPay-Delivery` header and the receiver's dedupe key."
          },
          "type": {
            "$ref": "#/components/schemas/EventType"
          },
          "paymentId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The payment the event is about; `null` for `subscription.*` events."
          },
          "status": {
            "$ref": "#/components/schemas/WebhookDeliveryStatus"
          },
          "attempts": {
            "type": "integer",
            "format": "int32",
            "description": "Delivery attempts made so far."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the event was enqueued."
          },
          "lastAttemptAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the most recent attempt ran."
          },
          "lastHttpStatus": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "HTTP status your endpoint returned on the most recent attempt; `null` if it never answered."
          },
          "lastError": {
            "type": [
              "string",
              "null"
            ],
            "description": "Transport-level failure reason of the most recent attempt (no answer at all), or `null`."
          },
          "lastResponseBody": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your endpoint's response body on the most recent attempt (truncated to 1000 characters), or `null`."
          },
          "nextAttemptAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Next retry time — set only while `pending` after at least one attempt."
          },
          "deliveredAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When a 2xx was received."
          },
          "payload": {
            "type": "string",
            "description": "The exact JSON body that was (or will be) POSTed, as a string — parse it to inspect. Byte-identical across attempts."
          }
        },
        "required": [
          "id",
          "type",
          "paymentId",
          "status",
          "attempts",
          "createdAt",
          "lastAttemptAt",
          "lastHttpStatus",
          "lastError",
          "lastResponseBody",
          "nextAttemptAt",
          "deliveredAt",
          "payload"
        ],
        "description": "One webhook outbox row (most recent attempt only, not a per-attempt history)."
      },
      "Product": {
        "type": "object",
        "properties": {
          "productId": {
            "type": "string",
            "description": "Product id (`prod_…`)."
          },
          "name": {
            "type": "string",
            "description": "Product name."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description shown under the amount in the checkout."
          },
          "active": {
            "type": "boolean",
            "description": "Deactivating a product takes all of its prices off sale."
          }
        },
        "required": [
          "productId",
          "name",
          "description",
          "active"
        ]
      },
      "Price": {
        "type": "object",
        "properties": {
          "priceId": {
            "type": "string",
            "description": "Price id (`price_…`)."
          },
          "productId": {
            "type": "string",
            "description": "The product this price belongs to."
          },
          "unitAmountCents": {
            "type": "integer",
            "format": "int64",
            "description": "Amount in integer USD cents."
          },
          "amount": {
            "$ref": "#/components/schemas/DisplayAmount"
          },
          "currency": {
            "type": "string",
            "enum": [
              "usd"
            ]
          },
          "acceptedNetworks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Network"
            },
            "description": "Networks the buyer may pay on; empty = no restriction."
          },
          "acceptedTokens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Token"
            },
            "description": "Tokens the buyer may pay with; empty = no restriction."
          },
          "type": {
            "$ref": "#/components/schemas/PriceType"
          },
          "interval": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Interval"
              },
              {
                "type": "null"
              }
            ],
            "description": "Billing interval for a recurring price; `null` for one-time prices."
          },
          "active": {
            "type": "boolean",
            "description": "Inactive prices refuse new checkouts (`400 price_inactive`)."
          }
        },
        "required": [
          "priceId",
          "productId",
          "unitAmountCents",
          "amount",
          "currency",
          "acceptedNetworks",
          "acceptedTokens",
          "type",
          "interval",
          "active"
        ],
        "description": "A fixed amount for a product. Immutable except `active`."
      },
      "PaymentLink": {
        "type": "object",
        "properties": {
          "paymentLinkId": {
            "type": "string",
            "description": "Payment link id (`plink_…`)."
          },
          "priceId": {
            "type": "string",
            "description": "The price this link sells."
          },
          "collectEmail": {
            "type": "boolean",
            "description": "Whether the hosted checkout asks for the buyer's email."
          },
          "active": {
            "type": "boolean",
            "description": "Deactivated links stop resolving at checkout."
          }
        },
        "required": [
          "paymentLinkId",
          "priceId",
          "collectEmail",
          "active"
        ]
      },
      "Recurring": {
        "type": "object",
        "properties": {
          "interval": {
            "$ref": "#/components/schemas/Interval"
          }
        },
        "required": [
          "interval"
        ],
        "description": "Present when the payment or price belongs to a subscription."
      },
      "Payment": {
        "type": "object",
        "properties": {
          "paymentId": {
            "type": "string",
            "description": "Payment id (`pay_…`). Unguessable: it is the capability for the public status, cancel, extend and simulate routes."
          },
          "status": {
            "$ref": "#/components/schemas/PaymentStatus"
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "network": {
            "$ref": "#/components/schemas/Network"
          },
          "token": {
            "$ref": "#/components/schemas/Token"
          },
          "contract": {
            "type": "string",
            "description": "The token's contract address (mint on Solana) in display form."
          },
          "payTo": {
            "type": "string",
            "description": "The receiving address the buyer must pay, in display form (lowercase hex on EVM, base58 on Tron and Solana)."
          },
          "amount": {
            "$ref": "#/components/schemas/DisplayAmount"
          },
          "amountBaseUnits": {
            "$ref": "#/components/schemas/BaseUnits"
          },
          "decimals": {
            "type": "integer",
            "format": "int32",
            "description": "Token decimals."
          },
          "txHash": {
            "type": [
              "string",
              "null"
            ],
            "description": "The settling transfer's hash once detected, else `null`."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "End of the reservation window (moves on extend; set to the cancel time on cancel)."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the payment was created."
          },
          "processing": {
            "type": "boolean",
            "description": "`true` while `PENDING` and the most recent on-chain check failed (RPC error): arrival can't currently be determined, so the widget shows a holding state instead of the countdown."
          },
          "sessionId": {
            "type": "string",
            "description": "Present when the payment was created from a checkout session."
          },
          "successUrl": {
            "type": "string",
            "description": "Present when the payment's checkout session has a `successUrl`."
          },
          "subscriptionId": {
            "type": "string",
            "description": "Present when the payment is a subscription fee invoice."
          },
          "recurring": {
            "$ref": "#/components/schemas/Recurring"
          },
          "branding": {
            "$ref": "#/components/schemas/Branding",
            "description": "The owning store's branding (present whenever the store has a branding record)."
          }
        },
        "required": [
          "paymentId",
          "status",
          "mode",
          "network",
          "token",
          "contract",
          "payTo",
          "amount",
          "amountBaseUnits",
          "decimals",
          "txHash",
          "expiresAt",
          "createdAt",
          "processing"
        ],
        "description": "A payment (buyer view). To pay, send exactly `amountBaseUnits` of `token` on `network` to `payTo` before `expiresAt`."
      },
      "BillingPayment": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Payment"
          },
          {
            "type": "object",
            "properties": {
              "tier": {
                "$ref": "#/components/schemas/PlanTier"
              },
              "interval": {
                "$ref": "#/components/schemas/Interval"
              }
            },
            "required": [
              "tier",
              "interval"
            ]
          }
        ],
        "description": "The fee payment for a HashPay plan, plus the tier and interval it buys."
      },
      "PaymentSummary": {
        "type": "object",
        "properties": {
          "paymentId": {
            "type": "string",
            "description": "Payment id (`pay_…`)."
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "network": {
            "$ref": "#/components/schemas/Network"
          },
          "token": {
            "$ref": "#/components/schemas/Token"
          },
          "payTo": {
            "type": "string",
            "description": "Receiving address in display form."
          },
          "amount": {
            "$ref": "#/components/schemas/DisplayAmount"
          },
          "status": {
            "$ref": "#/components/schemas/PaymentStatus"
          },
          "txHash": {
            "type": [
              "string",
              "null"
            ],
            "description": "Settling transfer hash, or `null`."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the payment was created."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "End of the reservation window."
          }
        },
        "required": [
          "paymentId",
          "mode",
          "network",
          "token",
          "payTo",
          "amount",
          "status",
          "txHash",
          "createdAt",
          "expiresAt"
        ],
        "description": "A payment in the store's history list."
      },
      "PaymentList": {
        "type": "object",
        "properties": {
          "payments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentSummary"
            },
            "description": "Newest first."
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `startAfter` to fetch the next page; `null` on the last page."
          }
        },
        "required": [
          "payments",
          "nextCursor"
        ]
      },
      "PaymentOption": {
        "type": "object",
        "properties": {
          "network": {
            "$ref": "#/components/schemas/Network"
          },
          "token": {
            "$ref": "#/components/schemas/Token"
          },
          "decimals": {
            "type": "integer",
            "format": "int32",
            "description": "Token decimals."
          }
        },
        "required": [
          "network",
          "token",
          "decimals"
        ],
        "description": "A (network, token) the buyer may pick."
      },
      "CheckoutInfo": {
        "type": "object",
        "properties": {
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "amount": {
            "$ref": "#/components/schemas/DisplayAmount"
          },
          "amountCents": {
            "type": "integer",
            "format": "int64",
            "description": "Amount in integer USD cents."
          },
          "currency": {
            "type": "string",
            "enum": [
              "usd"
            ]
          },
          "sellerName": {
            "type": "string",
            "description": "Who the buyer is paying: the store's branding display name, else the store name (never the account's business name)."
          },
          "productName": {
            "type": "string",
            "description": "Present when the amount comes from a catalog price."
          },
          "productDescription": {
            "type": "string",
            "description": "Present when the price's product has a non-blank description."
          },
          "recurring": {
            "$ref": "#/components/schemas/Recurring"
          },
          "collectEmail": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Present (always `true`) for a recurring price: the buyer's email is required to check out."
          },
          "branding": {
            "$ref": "#/components/schemas/Branding",
            "description": "Present whenever the store has a branding record."
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentOption"
            },
            "description": "Payable pairs: supported, allowed by the price, and receivable on this store (in test mode a store with no wallets at all gets synthetic test addresses)."
          },
          "acceptingPayments": {
            "type": "boolean",
            "description": "`false` when `options` is empty."
          },
          "unavailableReason": {
            "type": "string",
            "enum": [
              "no_wallet"
            ],
            "description": "Present only when `acceptingPayments` is `false`."
          }
        },
        "required": [
          "mode",
          "amount",
          "amountCents",
          "currency",
          "sellerName",
          "options",
          "acceptingPayments"
        ],
        "description": "Display data for the checkout chooser."
      },
      "CheckoutSession": {
        "type": "object",
        "properties": {
          "sessionId": {
            "type": "string",
            "description": "Session id (`cs_…`)."
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "complete",
              "expired"
            ],
            "description": "`complete` once a payment confirmed (see `paymentId`); `expired` once past `expiresAt` while still open."
          },
          "amountCents": {
            "type": "integer",
            "format": "int64",
            "description": "Amount in integer USD cents."
          },
          "currency": {
            "type": "string",
            "enum": [
              "usd"
            ]
          },
          "successUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where the widget sends the buyer after confirmation (as supplied; not validated)."
          },
          "paymentId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The payment that completed the session, else `null`."
          },
          "metadata": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Metadata"
              },
              {
                "type": "null"
              }
            ],
            "description": "As supplied at creation (`null` if none). Stamped, with `sessionId`, into the metadata of payments made from this session."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the session was created."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "Creation + 24 hours."
          }
        },
        "required": [
          "sessionId",
          "mode",
          "status",
          "amountCents",
          "currency",
          "successUrl",
          "paymentId",
          "metadata",
          "createdAt",
          "expiresAt"
        ],
        "description": "A server-created, dynamic-amount checkout."
      },
      "Plan": {
        "type": "object",
        "properties": {
          "tier": {
            "$ref": "#/components/schemas/PlanTier"
          },
          "ceilingCents": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Monthly received-volume ceiling in USD cents; `null` when unbounded."
          },
          "monthlyFeeCents": {
            "type": "integer",
            "format": "int64",
            "description": "Monthly fee in USD cents (0 for free and enterprise)."
          },
          "yearlyFeeCents": {
            "type": "integer",
            "format": "int64",
            "description": "Yearly fee in USD cents (0 for free and enterprise)."
          },
          "selfServe": {
            "type": "boolean",
            "description": "Whether `POST /v1/billing/subscribe` accepts this tier (`starter`, `pro`)."
          }
        },
        "required": [
          "tier",
          "ceilingCents",
          "monthlyFeeCents",
          "yearlyFeeCents",
          "selfServe"
        ]
      },
      "Subscription": {
        "type": "object",
        "properties": {
          "subscriptionId": {
            "type": "string",
            "description": "Subscription id."
          },
          "tier": {
            "$ref": "#/components/schemas/PlanTier",
            "description": "HashPay plan subscriptions only."
          },
          "priceId": {
            "type": "string",
            "description": "Store subscriptions only: the seller's recurring price."
          },
          "productName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Store subscriptions only: the price's product name, `null` if it can't be resolved."
          },
          "status": {
            "$ref": "#/components/schemas/SubscriptionStatus"
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "interval": {
            "$ref": "#/components/schemas/Interval"
          },
          "amount": {
            "$ref": "#/components/schemas/DisplayAmount"
          },
          "network": {
            "$ref": "#/components/schemas/Network"
          },
          "token": {
            "$ref": "#/components/schemas/Token"
          },
          "buyerEmail": {
            "type": "string",
            "description": "Where renewal reminders go."
          },
          "nextDueAt": {
            "type": "string",
            "format": "date-time",
            "description": "The next anniversary (renewal due date)."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the subscription was created."
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata",
            "description": "Present when the originating checkout supplied metadata."
          }
        },
        "required": [
          "subscriptionId",
          "status",
          "mode",
          "interval",
          "amount",
          "network",
          "token",
          "buyerEmail",
          "nextDueAt",
          "createdAt"
        ],
        "description": "A recurring agreement paid cycle by cycle (reminder-driven manual renewal, never an auto-charge). Either a HashPay plan (`tier` set) or a store subscription (`priceId`, `productName` set)."
      },
      "Usage": {
        "type": "object",
        "properties": {
          "tier": {
            "$ref": "#/components/schemas/PlanTier",
            "description": "The stored tier."
          },
          "effectiveTier": {
            "$ref": "#/components/schemas/PlanTier",
            "description": "The tier gating checkout right now (a lapsed paid tier counts as `free`)."
          },
          "monthlyVolumeCents": {
            "type": "integer",
            "format": "int64",
            "description": "USD cents received this calendar month (UTC)."
          },
          "ceilingCents": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Ceiling of `effectiveTier` in USD cents; `null` when unbounded."
          },
          "txCount": {
            "type": "integer",
            "format": "int32",
            "description": "Confirmed live transactions counted (information only)."
          },
          "paidPeriodEnd": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the paid tier runs out, or `null`."
          },
          "subscription": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Subscription"
              },
              {
                "type": "null"
              }
            ],
            "description": "The account's current HashPay plan subscription, or `null`."
          }
        },
        "required": [
          "tier",
          "effectiveTier",
          "monthlyVolumeCents",
          "ceilingCents",
          "txCount",
          "paidPeriodEnd",
          "subscription"
        ]
      },
      "RenewalInfo": {
        "type": "object",
        "properties": {
          "subscriptionId": {
            "type": "string",
            "description": "Subscription id."
          },
          "mode": {
            "$ref": "#/components/schemas/Mode"
          },
          "sellerName": {
            "type": "string",
            "description": "`HashPay` for a plan; else the store's display name, the store name, or `your seller`."
          },
          "planName": {
            "type": "string",
            "description": "Plan label, e.g. `Pro (month)`, or the product name (`Subscription` if unresolvable)."
          },
          "tier": {
            "$ref": "#/components/schemas/PlanTier",
            "description": "HashPay plans only."
          },
          "priceId": {
            "type": "string",
            "description": "Store subscriptions only."
          },
          "branding": {
            "$ref": "#/components/schemas/Branding",
            "description": "Store subscriptions whose store has a branding record only."
          },
          "interval": {
            "$ref": "#/components/schemas/Interval"
          },
          "amount": {
            "$ref": "#/components/schemas/DisplayAmount"
          },
          "amountCents": {
            "type": "integer",
            "format": "int64",
            "description": "Amount in integer USD cents."
          },
          "currency": {
            "type": "string",
            "enum": [
              "usd"
            ]
          },
          "network": {
            "$ref": "#/components/schemas/Network"
          },
          "token": {
            "$ref": "#/components/schemas/Token"
          },
          "decimals": {
            "type": "integer",
            "format": "int32",
            "description": "Token decimals."
          },
          "nextDueAt": {
            "type": "string",
            "format": "date-time",
            "description": "The next anniversary."
          },
          "status": {
            "$ref": "#/components/schemas/SubscriptionStatus"
          },
          "canRenew": {
            "type": "boolean",
            "description": "`false` only for `INCOMPLETE` (never paid). `CANCELED` is renewable — that is the restore path."
          }
        },
        "required": [
          "subscriptionId",
          "mode",
          "sellerName",
          "planName",
          "interval",
          "amount",
          "amountCents",
          "currency",
          "network",
          "token",
          "decimals",
          "nextDueAt",
          "status",
          "canRenew"
        ]
      },
      "Revoked": {
        "type": "object",
        "properties": {
          "revoked": {
            "type": "string",
            "description": "The id that was revoked."
          }
        },
        "required": [
          "revoked"
        ]
      },
      "Ok": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          }
        },
        "required": [
          "ok"
        ]
      },
      "SetupStepEmailVerified": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "const": "email_verified"
          },
          "required": {
            "type": "boolean",
            "const": true,
            "description": "Required before live payments (`true`) or recommended (`false`)."
          },
          "done": {
            "type": "boolean",
            "description": "Whether the step is complete."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable status, or what to do next."
          }
        },
        "required": [
          "id",
          "required",
          "done",
          "detail"
        ],
        "description": "Required. The account owner verified their email. Live keys answer `403 email_unverified` until the owner clicks the verification link — only a human can do this."
      },
      "SetupStepWallets": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "const": "wallets"
          },
          "required": {
            "type": "boolean",
            "const": true,
            "description": "Required before live payments (`true`) or recommended (`false`)."
          },
          "done": {
            "type": "boolean",
            "description": "Whether the step is complete."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable status, or what to do next."
          },
          "networks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Network"
            },
            "description": "Networks with at least one receiving wallet on this store."
          }
        },
        "required": [
          "id",
          "required",
          "done",
          "detail",
          "networks"
        ],
        "description": "Required. At least one receiving wallet on this store."
      },
      "SetupStepWebhookEndpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "const": "webhook_endpoint"
          },
          "required": {
            "type": "boolean",
            "const": false,
            "description": "Required before live payments (`true`) or recommended (`false`)."
          },
          "done": {
            "type": "boolean",
            "description": "Whether the step is complete."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable status, or what to do next."
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "The registered webhook URL, or `null`.",
            "format": "uri"
          },
          "activeSecrets": {
            "type": "integer",
            "format": "int32",
            "description": "Active signing secrets (0–2)."
          }
        },
        "required": [
          "id",
          "required",
          "done",
          "detail",
          "url",
          "activeSecrets"
        ],
        "description": "Recommended. Done when a URL is registered and at least one signing secret is active."
      },
      "SetupStepTestPayment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "const": "test_payment"
          },
          "required": {
            "type": "boolean",
            "const": false,
            "description": "Required before live payments (`true`) or recommended (`false`)."
          },
          "done": {
            "type": "boolean",
            "description": "Whether the step is complete."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable status, or what to do next."
          },
          "paymentId": {
            "type": [
              "string",
              "null"
            ],
            "description": "The most recent CONFIRMED test-mode payment for this store, or `null`."
          }
        },
        "required": [
          "id",
          "required",
          "done",
          "detail",
          "paymentId"
        ],
        "description": "Recommended. A test-mode payment for this store reached `CONFIRMED` (e.g. via `POST /v1/test/payments/{id}/simulate`)."
      },
      "SetupDeliveryRef": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string",
            "description": "The delivery's event id (`<paymentId>:payment.confirmed`)."
          },
          "status": {
            "$ref": "#/components/schemas/WebhookDeliveryStatus"
          },
          "httpStatus": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "HTTP status your endpoint returned on the most recent attempt, or `null`."
          },
          "at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the most recent attempt ran (or the delivery succeeded), or `null`."
          }
        },
        "required": [
          "eventId",
          "status",
          "httpStatus",
          "at"
        ],
        "description": "The most recent `payment.confirmed` delivery to this store's endpoint."
      },
      "SetupStepWebhookVerified": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "const": "webhook_verified"
          },
          "required": {
            "type": "boolean",
            "const": false,
            "description": "Required before live payments (`true`) or recommended (`false`)."
          },
          "done": {
            "type": "boolean",
            "description": "Whether the step is complete."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable status, or what to do next."
          },
          "lastConfirmedDelivery": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SetupDeliveryRef"
              },
              {
                "type": "null"
              }
            ],
            "description": "`null` when no `payment.confirmed` delivery exists yet."
          }
        },
        "required": [
          "id",
          "required",
          "done",
          "detail",
          "lastConfirmedDelivery"
        ],
        "description": "Recommended. Done when the most recent `payment.confirmed` delivery to this store's endpoint was acknowledged with a 2xx."
      },
      "SetupStepEmbedInstalled": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "const": "embed_installed"
          },
          "required": {
            "type": "boolean",
            "const": false,
            "description": "Required before live payments (`true`) or recommended (`false`)."
          },
          "done": {
            "type": "boolean",
            "description": "Whether the step is complete."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable status, or what to do next."
          },
          "seenAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the checkout script was first seen running on a page with this store's publishable key, or `null`."
          }
        },
        "required": [
          "id",
          "required",
          "done",
          "detail",
          "seenAt"
        ],
        "description": "Recommended. The checkout script has run on a page with this store's publishable key."
      },
      "SetupStep": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/SetupStepEmailVerified"
          },
          {
            "$ref": "#/components/schemas/SetupStepWallets"
          },
          {
            "$ref": "#/components/schemas/SetupStepWebhookEndpoint"
          },
          {
            "$ref": "#/components/schemas/SetupStepTestPayment"
          },
          {
            "$ref": "#/components/schemas/SetupStepWebhookVerified"
          },
          {
            "$ref": "#/components/schemas/SetupStepEmbedInstalled"
          }
        ],
        "discriminator": {
          "propertyName": "id",
          "mapping": {
            "email_verified": "#/components/schemas/SetupStepEmailVerified",
            "wallets": "#/components/schemas/SetupStepWallets",
            "webhook_endpoint": "#/components/schemas/SetupStepWebhookEndpoint",
            "test_payment": "#/components/schemas/SetupStepTestPayment",
            "webhook_verified": "#/components/schemas/SetupStepWebhookVerified",
            "embed_installed": "#/components/schemas/SetupStepEmbedInstalled"
          }
        },
        "description": "One checklist step: `id`, `required`, `done`, `detail`, plus the step's own fields."
      },
      "SetupChecklist": {
        "type": "object",
        "properties": {
          "storeId": {
            "type": "string",
            "description": "Store id (`store_…`)."
          },
          "readyForLive": {
            "type": "boolean",
            "description": "`true` when every required step is done."
          },
          "next": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SetupStepId"
              },
              {
                "type": "null"
              }
            ],
            "description": "Id of the first step not yet done (required or recommended); `null` when everything is done."
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SetupStep"
            },
            "minItems": 6,
            "maxItems": 6,
            "description": "Always in this order: `email_verified`, `wallets`, `webhook_endpoint`, `test_payment`, `webhook_verified`, `embed_installed`."
          }
        },
        "required": [
          "storeId",
          "readyForLive",
          "next",
          "steps"
        ]
      },
      "CheckoutInfoRequest": {
        "type": "object",
        "properties": {
          "publishableKey": {
            "type": "string",
            "description": "The store's publishable key (`pk_test_…` / `pk_live_…`). It alone decides which store this checkout belongs to."
          },
          "priceId": {
            "type": "string",
            "description": "A catalog price (`price_…`) of the key's store."
          },
          "paymentLinkId": {
            "type": "string",
            "description": "A payment link (`plink_…`); resolves to its price."
          },
          "sessionId": {
            "type": "string",
            "description": "A checkout session (`cs_…`) minted by the seller's server with a secret key of the same store and mode."
          },
          "amount": {
            "type": "integer",
            "format": "int64",
            "description": "Open amount in integer USD cents (> 0), set by the browser. Refused (`403 open_amount_disabled`) when the store is in strict mode.",
            "minimum": 1
          },
          "currency": {
            "type": "string",
            "description": "Only meaningful with `amount`; must be `usd` (case-insensitive) when sent."
          },
          "network": {
            "type": "string",
            "description": "Accepted for symmetry with `POST /v1/checkout`; ignored here."
          },
          "token": {
            "type": "string",
            "description": "Accepted for symmetry with `POST /v1/checkout`; ignored here."
          },
          "ttlMinutes": {
            "type": "integer",
            "format": "int32",
            "description": "Accepted for symmetry with `POST /v1/checkout`; ignored here."
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata",
            "description": "Validated (limits, reserved keys) but not stored here."
          },
          "buyerEmail": {
            "type": "string",
            "description": "Accepted for symmetry with `POST /v1/checkout`; ignored here."
          }
        },
        "additionalProperties": false,
        "required": [
          "publishableKey"
        ],
        "description": "Exactly one amount source: `amount`, `priceId`, `paymentLinkId` or `sessionId`.",
        "oneOf": [
          {
            "required": [
              "amount"
            ]
          },
          {
            "required": [
              "priceId"
            ]
          },
          {
            "required": [
              "paymentLinkId"
            ]
          },
          {
            "required": [
              "sessionId"
            ]
          }
        ]
      },
      "CheckoutRequest": {
        "type": "object",
        "properties": {
          "publishableKey": {
            "type": "string",
            "description": "The store's publishable key (`pk_test_…` / `pk_live_…`)."
          },
          "priceId": {
            "type": "string",
            "description": "A catalog price (`price_…`). A recurring price opens a subscription and requires `buyerEmail`."
          },
          "paymentLinkId": {
            "type": "string",
            "description": "A payment link (`plink_…`); resolves to its price."
          },
          "sessionId": {
            "type": "string",
            "description": "A checkout session (`cs_…`) of the same store and mode; its amount is used and `sessionId` is stamped into the payment's metadata."
          },
          "amount": {
            "type": "integer",
            "format": "int64",
            "description": "Open amount in integer USD cents (> 0). Refused (`403 open_amount_disabled`) when the store is in strict mode.",
            "minimum": 1
          },
          "currency": {
            "type": "string",
            "description": "Only meaningful with `amount`; must be `usd` (case-insensitive) when sent."
          },
          "network": {
            "$ref": "#/components/schemas/Network",
            "description": "The chain the buyer picked (case-insensitive)."
          },
          "token": {
            "$ref": "#/components/schemas/Token",
            "description": "The token the buyer picked (case-insensitive)."
          },
          "ttlMinutes": {
            "type": "integer",
            "format": "int32",
            "description": "Reservation window in minutes, clamped to 5–60. Default: 60; for a subscription's first invoice, 24 hours when omitted."
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata",
            "description": "Stored on the payment and echoed on its webhooks. With `sessionId` it is ignored in favor of the session's own metadata."
          },
          "buyerEmail": {
            "type": "string",
            "description": "Required when the price is recurring: where renewal reminders go.",
            "format": "email"
          }
        },
        "additionalProperties": false,
        "required": [
          "publishableKey",
          "network",
          "token"
        ],
        "description": "Exactly one amount source: `amount`, `priceId`, `paymentLinkId` or `sessionId`.",
        "oneOf": [
          {
            "required": [
              "amount"
            ]
          },
          {
            "required": [
              "priceId"
            ]
          },
          {
            "required": [
              "paymentLinkId"
            ]
          },
          {
            "required": [
              "sessionId"
            ]
          }
        ]
      },
      "WidgetEventRequest": {
        "type": "object",
        "properties": {
          "event": {
            "type": "string",
            "description": "Lifecycle event name (logged; dropped when blank)."
          },
          "publishableKey": {
            "type": "string",
            "description": "The widget's publishable key. Events with an unresolvable key are dropped."
          },
          "paymentSessionId": {
            "type": "string",
            "description": "The payment or session the event concerns."
          },
          "timestamp": {
            "type": "integer",
            "format": "int64",
            "description": "Client timestamp."
          },
          "locale": {
            "type": "string",
            "description": "Widget locale."
          },
          "mode": {
            "type": "string",
            "description": "Widget mode."
          }
        },
        "additionalProperties": false
      },
      "EmbedHelloRequest": {
        "type": "object",
        "properties": {
          "publishableKey": {
            "type": "string",
            "description": "The publishable key the embed snippet was loaded with."
          }
        },
        "additionalProperties": false
      },
      "CheckoutSessionRequest": {
        "type": "object",
        "properties": {
          "amountCents": {
            "type": "integer",
            "format": "int64",
            "description": "Amount in integer USD cents; must be > 0.",
            "minimum": 1
          },
          "successUrl": {
            "type": "string",
            "description": "Where the widget sends the buyer after confirmation (stored as supplied; not validated)."
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          }
        },
        "additionalProperties": false,
        "required": [
          "amountCents"
        ]
      },
      "AccountUpdateRequest": {
        "type": "object",
        "properties": {
          "businessName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Business name."
          },
          "supportEmail": {
            "type": [
              "string",
              "null"
            ],
            "description": "Support email. Also the default recipient of store email notifications."
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "Country code."
          },
          "website": {
            "type": [
              "string",
              "null"
            ],
            "description": "Website."
          }
        },
        "additionalProperties": false,
        "description": "Full replacement of the profile: all four fields are written, so an omitted field is cleared to `null`. Send the complete profile."
      },
      "StoreCreateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Store name (trimmed; must not be blank)."
          },
          "openAmountDisabled": {
            "type": "boolean",
            "description": "Accepted but ignored on create (new stores allow open amounts); set it with `PUT /v1/stores/{storeId}`."
          }
        },
        "additionalProperties": false,
        "required": [
          "name"
        ]
      },
      "StoreUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "New name; omitted or blank leaves it unchanged."
          },
          "openAmountDisabled": {
            "type": "boolean",
            "description": "Strict mode; omitted leaves it unchanged."
          }
        },
        "additionalProperties": false
      },
      "WalletAddRequest": {
        "type": "object",
        "properties": {
          "network": {
            "$ref": "#/components/schemas/Network",
            "description": "One network (case-insensitive). Mutually exclusive with `networks`."
          },
          "networks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Network"
            },
            "minItems": 1,
            "description": "Several networks for the same address (e.g. one EVM address on several EVM chains). Mutually exclusive with `network`. Duplicates are ignored."
          },
          "address": {
            "type": "string",
            "description": "The receiving address, verbatim from the seller's wallet. Mixed-case `0x…` input must pass its EIP-55 checksum; Tron accepts base58 (`T…`)."
          },
          "label": {
            "type": "string",
            "description": "Optional label (stored as an empty string when omitted)."
          }
        },
        "additionalProperties": false,
        "required": [
          "address"
        ],
        "description": "Exactly one of `network` or `networks`, plus `address`.",
        "oneOf": [
          {
            "required": [
              "network"
            ],
            "not": {
              "required": [
                "networks"
              ]
            }
          },
          {
            "required": [
              "networks"
            ],
            "not": {
              "required": [
                "network"
              ]
            }
          }
        ]
      },
      "WalletCopyRequest": {
        "type": "object",
        "properties": {
          "fromStoreId": {
            "type": "string",
            "description": "Another store of the same account to copy wallets from."
          }
        },
        "additionalProperties": false,
        "required": [
          "fromStoreId"
        ]
      },
      "KeyCreateRequest": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "description": "`publishable` or `secret` (case-insensitive). Anything other than `secret` — including omission — mints a publishable key.",
            "enum": [
              "publishable",
              "secret"
            ],
            "default": "publishable"
          },
          "mode": {
            "type": "string",
            "description": "`test` or `live` (case-insensitive); default `test`.",
            "enum": [
              "test",
              "live"
            ],
            "default": "test"
          }
        },
        "additionalProperties": false
      },
      "WebhookUrlRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Public `https://` endpoint that receives HashPay's POSTs.",
            "format": "uri"
          }
        },
        "additionalProperties": false,
        "required": [
          "url"
        ]
      },
      "BrandingRequest": {
        "type": "object",
        "properties": {
          "displayName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Name shown to buyers. Omitted or `null` clears it."
          },
          "logoUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "Logo URL. Omitted or `null` clears it."
          },
          "color": {
            "type": [
              "string",
              "null"
            ],
            "description": "Accent color, e.g. `#251160`. Omitted or `null` clears it."
          }
        },
        "additionalProperties": false,
        "description": "`displayName`, `logoUrl` and `color` are replaced as a set: an omitted one is cleared."
      },
      "NotificationsRequest": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Turn event emails on or off; omitted leaves it unchanged. Enabling with no events selected selects `payment.confirmed`, `payment.underpaid`, `payment.overpaid`."
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Recipient override; omitted leaves it unchanged; an empty string clears it back to the account's `supportEmail`."
          },
          "events": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/EventType"
            },
            "description": "Replaces the selected events (blanks and duplicates dropped); omitted leaves them unchanged. An unknown event is `400 bad_request`."
          }
        },
        "additionalProperties": false,
        "description": "Partial update: every field is optional and an omitted field keeps its stored value."
      },
      "DomainRequest": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "description": "A hostname or a full URL (its host is used, lowercased)."
          }
        },
        "additionalProperties": false,
        "required": [
          "domain"
        ]
      },
      "ProductCreateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Product name (trimmed; must not be blank)."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional description."
          }
        },
        "additionalProperties": false,
        "required": [
          "name"
        ]
      },
      "ProductUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "New name; omitted or blank leaves it unchanged."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "New description; omitted leaves it unchanged."
          },
          "active": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Deactivating takes all of the product's prices off sale."
          }
        },
        "additionalProperties": false,
        "description": "Partial update: omitted fields are unchanged."
      },
      "PriceCreateRequest": {
        "type": "object",
        "properties": {
          "productId": {
            "type": "string",
            "description": "A product of this store."
          },
          "unitAmountCents": {
            "type": "integer",
            "format": "int64",
            "description": "Amount in integer USD cents; must be > 0.",
            "minimum": 1
          },
          "acceptedNetworks": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict the buyer's networks (case-insensitive ids). Omitted or empty = no restriction. Unrecognized ids are silently dropped."
          },
          "acceptedTokens": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Restrict the buyer's tokens (case-insensitive ids). Omitted or empty = no restriction. Unrecognized ids are silently dropped."
          },
          "type": {
            "type": "string",
            "description": "`one_time` (default) or `recurring` (case-insensitive).",
            "enum": [
              "one_time",
              "recurring"
            ],
            "default": "one_time"
          },
          "interval": {
            "type": "string",
            "description": "Recurring prices only: `month` (default) or `year`. Sending it with a one-time price is `400 bad_request`.",
            "enum": [
              "month",
              "year"
            ]
          }
        },
        "additionalProperties": false,
        "required": [
          "productId",
          "unitAmountCents"
        ]
      },
      "PriceUpdateRequest": {
        "type": "object",
        "properties": {
          "active": {
            "type": "boolean",
            "description": "The only mutable field of a price."
          }
        },
        "additionalProperties": false,
        "required": [
          "active"
        ]
      },
      "PaymentLinkCreateRequest": {
        "type": "object",
        "properties": {
          "priceId": {
            "type": "string",
            "description": "A price of this store."
          },
          "collectEmail": {
            "type": "boolean",
            "description": "Ask the buyer for their email (default `false`).",
            "default": false
          }
        },
        "additionalProperties": false,
        "required": [
          "priceId"
        ]
      },
      "PaymentLinkUpdateRequest": {
        "type": "object",
        "properties": {
          "active": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Deactivate or reactivate the link."
          },
          "collectEmail": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Ask the buyer for their email."
          }
        },
        "additionalProperties": false,
        "description": "Partial update: omitted fields are unchanged."
      },
      "SubscribeRequest": {
        "type": "object",
        "properties": {
          "tier": {
            "type": "string",
            "description": "`starter` or `pro` (case-insensitive). `free`/`enterprise` answer `400 bad_tier`.",
            "enum": [
              "starter",
              "pro"
            ]
          },
          "interval": {
            "type": "string",
            "description": "`month` or `year`. Defaults to `month` for a new subscription; an upgrade keeps the current interval and refuses a different one.",
            "enum": [
              "month",
              "year"
            ]
          },
          "network": {
            "$ref": "#/components/schemas/Network",
            "description": "Chain to pay the fee on (case-insensitive)."
          },
          "token": {
            "$ref": "#/components/schemas/Token",
            "description": "Token to pay the fee with (case-insensitive)."
          }
        },
        "additionalProperties": false,
        "required": [
          "tier",
          "network",
          "token"
        ]
      }
    }
  }
}
