{
  "openapi": "3.0.3",
  "info": {
    "title": "Koinzend API",
    "description": "Financial-grade payment infrastructure API for Ghana. Supports mobile money (MTN MoMo, Telecel Cash, AirtelTigo Money), bank transfers via GhIPSS, card payments, recurring subscriptions, and invoicing.\n\n**Test mode / live mode:** API keys determine mode automatically (`sk_test_` = test, `sk_live_` = live). JWT-authenticated requests default to live mode; add `?mode=test` query parameter or `X-Mode: test` header to access test data. Every response object includes a `livemode` field. Test and live data are fully isolated.",
    "version": "1.0.0",
    "contact": { "name": "Koinzend Support", "email": "support@koinzend.com" }
  },
  "servers": [
    { "url": "http://localhost:8080", "description": "Local development" }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "tags": [
    { "name": "Payments", "description": "Payment initiation, tracking, and webhook handling" },
    { "name": "Customers", "description": "Customer profile management" },
    { "name": "Plans", "description": "Billing plan catalog for recurring subscriptions" },
    { "name": "Products", "description": "Manage merchant product catalog" },
    { "name": "Prices", "description": "Manage product pricing" },
    { "name": "Subscriptions", "description": "Recurring billing and subscription lifecycle" },
    { "name": "Invoices", "description": "Invoice creation, finalization, and payment tracking" },
    { "name": "Webhooks", "description": "Provider callback handling" },
    { "name": "Checkouts", "description": "Hosted checkout sessions for payments and subscriptions" },
    { "name": "Refunds", "description": "Refund management for successful payments" },
    { "name": "Payouts", "description": "Send money to bank accounts and mobile wallets" },
    { "name": "API Keys", "description": "API key management" },
    { "name": "Balance", "description": "Account balance and transaction history" },
    { "name": "Payment Links", "description": "No-code payment pages for merchants" },
    { "name": "Payment Links (Public)", "description": "Public payer-facing payment link endpoints" },
    { "name": "Webhook Endpoints", "description": "Webhook endpoint registration and management" },
    { "name": "Allowed Origins", "description": "CORS origin management for embedded widgets" },
    { "name": "Tax Rates", "description": "Tax rate configuration and management" },
    { "name": "Merchants", "description": "Merchant registration, authentication, and profile management" }
  ],
  "paths": {
    "/v1/payments": {
      "post": {
        "tags": [ "Payments" ],
        "summary": "Initiate a payment",
        "description": "Creates a new payment. Requires an Idempotency-Key header to prevent duplicate charges.",
        "operationId": "initiatePayment",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique key to ensure idempotent requests (1-64 chars, alphanumeric with - and _)",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[A-Za-z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/InitiatePaymentRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "409": {
            "description": "Duplicate idempotency key",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      },
      "get": {
        "tags": [ "Payments" ],
        "summary": "List payments",
        "operationId": "listPayments",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "status",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/PaymentStatus" }
          },
          {
            "name": "payment_method",
            "in": "query",
            "schema": { "type": "string" }
          },
          {
            "name": "min_amount",
            "in": "query",
            "schema": { "type": "number" }
          },
          {
            "name": "max_amount",
            "in": "query",
            "schema": { "type": "number" }
          },
          {
            "name": "from_date",
            "in": "query",
            "schema": { "type": "string", "format": "date-time" }
          },
          {
            "name": "to_date",
            "in": "query",
            "schema": { "type": "string", "format": "date-time" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of payments",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedPaymentResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/payments/{id}": {
      "get": {
        "tags": [ "Payments" ],
        "summary": "Get a payment",
        "operationId": "getPayment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/webhooks/{provider}": {
      "post": {
        "tags": [ "Webhooks" ],
        "summary": "Handle provider webhook",
        "description": "Receives callbacks from payment providers (mtn_momo, telecel_cash, airteltigo_money, bank_transfer).",
        "operationId": "handleWebhook",
        "security": [],
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [ "mtn_momo", "telecel_cash", "airteltigo_money", "bank_transfer" ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": { "type": "string", "format": "binary" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "received": { "type": "boolean" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/customers": {
      "post": {
        "tags": [ "Customers" ],
        "summary": "Create a customer",
        "operationId": "createCustomer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateCustomerRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Customer created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CustomerResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Customers" ],
        "summary": "List customers",
        "operationId": "listCustomers",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [ "active", "suspended" ]
            }
          },
          {
            "name": "customer_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [ "individual", "business" ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of customers",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedCustomerResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/customers/{id}": {
      "get": {
        "tags": [ "Customers" ],
        "summary": "Get a customer",
        "operationId": "getCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CustomerResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "put": {
        "tags": [ "Customers" ],
        "summary": "Update a customer",
        "description": "Partial update — only fields present in the request are changed.",
        "operationId": "updateCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdateCustomerRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Customer updated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CustomerResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "tags": [ "Customers" ],
        "summary": "Delete a customer",
        "description": "Hard deletes a customer. Fails if the customer has associated subscriptions or invoices.",
        "operationId": "deleteCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "204": { "description": "Customer deleted" },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/plans": {
      "post": {
        "tags": [ "Plans" ],
        "summary": "Create a plan",
        "description": "Creates a reusable billing plan that defines subscription terms (name, interval, trial period). Amount is not on the plan — it is specified per subscription or checkout.",
        "operationId": "createPlan",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreatePlanRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Plan created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PlanResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Plans" ],
        "summary": "List plans",
        "operationId": "listPlans",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "active",
            "in": "query",
            "schema": { "type": "boolean" },
            "description": "Filter by active status"
          },
          {
            "name": "billing_interval",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/BillingInterval" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of plans",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedPlanResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/plans/{id}": {
      "get": {
        "tags": [ "Plans" ],
        "summary": "Get a plan",
        "operationId": "getPlan",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Plan details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PlanResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": [ "Plans" ],
        "summary": "Update a plan",
        "operationId": "updatePlan",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdatePlanRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plan updated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PlanResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/products": {
      "post": {
        "tags": [ "Products" ],
        "summary": "Create a product",
        "operationId": "createProduct",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateProductRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Product created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProductResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Products" ],
        "summary": "List products",
        "operationId": "listProducts",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "active",
            "in": "query",
            "description": "Filter by active status",
            "schema": { "type": "boolean" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of products",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedProductResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/products/{id}": {
      "get": {
        "tags": [ "Products" ],
        "summary": "Get a product",
        "operationId": "getProduct",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Product details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProductResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": [ "Products" ],
        "summary": "Update a product",
        "operationId": "updateProduct",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdateProductRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Product updated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProductResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "tags": [ "Products" ],
        "summary": "Delete a product",
        "operationId": "deleteProduct",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Product deleted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/DeletedResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/prices": {
      "post": {
        "tags": [ "Prices" ],
        "summary": "Create a price",
        "operationId": "createPrice",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreatePriceRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Price created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PriceResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Prices" ],
        "summary": "List prices",
        "operationId": "listPrices",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "active",
            "in": "query",
            "description": "Filter by active status",
            "schema": { "type": "boolean" }
          },
          {
            "name": "product_id",
            "in": "query",
            "description": "Filter by product ID",
            "schema": { "type": "string", "format": "uuid" }
          },
          {
            "name": "price_type",
            "in": "query",
            "description": "Filter by price type",
            "schema": {
              "type": "string",
              "enum": [ "one_time", "recurring" ]
            }
          },
          {
            "name": "currency",
            "in": "query",
            "description": "Filter by currency",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of prices",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedPriceResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/prices/{id}": {
      "get": {
        "tags": [ "Prices" ],
        "summary": "Get a price",
        "operationId": "getPrice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Price details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PriceResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": [ "Prices" ],
        "summary": "Update a price",
        "operationId": "updatePrice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdatePriceRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Price updated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PriceResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/subscriptions": {
      "post": {
        "tags": [ "Subscriptions" ],
        "summary": "Create a subscription",
        "operationId": "createSubscription",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateSubscriptionRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscription created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Subscriptions" ],
        "summary": "List subscriptions",
        "operationId": "listSubscriptions",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "status",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/SubscriptionStatus" }
          },
          {
            "name": "customer_id",
            "in": "query",
            "schema": { "type": "string", "format": "uuid" }
          },
          {
            "name": "billing_interval",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [ "daily", "weekly", "monthly", "quarterly", "yearly" ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of subscriptions",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedSubscriptionResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/subscriptions/{id}": {
      "get": {
        "tags": [ "Subscriptions" ],
        "summary": "Get a subscription",
        "operationId": "getSubscription",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/subscriptions/{id}/cancel": {
      "post": {
        "tags": [ "Subscriptions" ],
        "summary": "Cancel a subscription",
        "operationId": "cancelSubscription",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription cancelled",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/subscriptions/{id}/pause": {
      "post": {
        "tags": [ "Subscriptions" ],
        "summary": "Pause a subscription",
        "description": "Only active subscriptions can be paused.",
        "operationId": "pauseSubscription",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription paused",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/subscriptions/{id}/resume": {
      "post": {
        "tags": [ "Subscriptions" ],
        "summary": "Resume a subscription",
        "description": "Only paused subscriptions can be resumed. Resets the billing period.",
        "operationId": "resumeSubscription",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription resumed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/subscriptions/{id}/cancel-at-period-end": {
      "post": {
        "tags": [ "Subscriptions" ],
        "summary": "Schedule cancellation at period end",
        "description": "Schedules the subscription for cancellation at the end of the current billing period. The subscription stays active until then. Returns 409 if a pending downgrade exists.",
        "operationId": "cancelAtPeriodEnd",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancellation scheduled",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": {
            "description": "A pending downgrade exists — remove it first",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [ "Subscriptions" ],
        "summary": "Undo scheduled cancellation",
        "description": "Removes a previously scheduled period-end cancellation.",
        "operationId": "undoCancelAtPeriodEnd",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancellation unscheduled",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/subscriptions/{id}/downgrade": {
      "post": {
        "tags": [ "Subscriptions" ],
        "summary": "Schedule a downgrade at period end",
        "description": "Schedules a plan/amount change at the end of the current billing period. Current price applies until then. Returns 409 if a pending cancellation exists.",
        "operationId": "scheduleDowngrade",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/DowngradeRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Downgrade scheduled",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": {
            "description": "A pending cancellation exists — remove it first",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [ "Subscriptions" ],
        "summary": "Undo scheduled downgrade",
        "description": "Removes a previously scheduled period-end downgrade.",
        "operationId": "undoDowngrade",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Downgrade unscheduled",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SubscriptionResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/invoices": {
      "post": {
        "tags": [ "Invoices" ],
        "summary": "Create an invoice",
        "description": "Creates a new invoice in Draft status with line items.",
        "operationId": "createInvoice",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateInvoiceRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invoice created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InvoiceResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Invoices" ],
        "summary": "List invoices",
        "operationId": "listInvoices",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "status",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/InvoiceStatus" }
          },
          {
            "name": "customer_id",
            "in": "query",
            "schema": { "type": "string", "format": "uuid" }
          },
          {
            "name": "subscription_id",
            "in": "query",
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of invoices",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedInvoiceResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/invoices/{id}": {
      "get": {
        "tags": [ "Invoices" ],
        "summary": "Get an invoice",
        "description": "Returns the invoice with all line items.",
        "operationId": "getInvoice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice details with line items",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InvoiceResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/invoices/{id}/finalize": {
      "post": {
        "tags": [ "Invoices" ],
        "summary": "Finalize an invoice",
        "description": "Moves a draft invoice to open status, making it ready for payment.",
        "operationId": "finalizeInvoice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice finalized",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InvoiceResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/invoices/{id}/void": {
      "post": {
        "tags": [ "Invoices" ],
        "summary": "Void an invoice",
        "description": "Voids a draft or open invoice. Cannot be undone.",
        "operationId": "voidInvoice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice voided",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InvoiceResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/invoices/{id}/mark-paid": {
      "post": {
        "tags": [ "Invoices" ],
        "summary": "Mark an invoice as paid",
        "description": "Only open invoices can be marked as paid.",
        "operationId": "markInvoicePaid",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice marked as paid",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InvoiceResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/invoices/{id}/mark-uncollectible": {
      "post": {
        "tags": [ "Invoices" ],
        "summary": "Mark an invoice as uncollectible",
        "description": "Only open invoices can be marked as uncollectible.",
        "operationId": "markInvoiceUncollectible",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Invoice marked as uncollectible",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InvoiceResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/checkouts": {
      "post": {
        "tags": [ "Checkouts" ],
        "summary": "Create a checkout session",
        "description": "Creates a hosted checkout session for a payment or subscription.",
        "operationId": "createCheckout",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique key to ensure idempotent requests (1-64 chars, alphanumeric with - and _)",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[A-Za-z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateCheckoutRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Checkout session created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CheckoutResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Checkouts" ],
        "summary": "List checkouts",
        "operationId": "listCheckouts",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "status",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/CheckoutStatus" }
          },
          {
            "name": "checkout_type",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/CheckoutType" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of checkouts",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedCheckoutResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/checkouts/{id}": {
      "get": {
        "tags": [ "Checkouts" ],
        "summary": "Get a checkout",
        "operationId": "getCheckout",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Checkout details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CheckoutResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/checkouts/{id}/expire": {
      "post": {
        "tags": [ "Checkouts" ],
        "summary": "Expire a checkout",
        "description": "Manually expires an open checkout session.",
        "operationId": "expireCheckout",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Checkout expired",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CheckoutResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/refunds": {
      "post": {
        "tags": [ "Refunds" ],
        "summary": "Create a refund",
        "description": "Creates a refund for a successful payment. Supports full and partial refunds. Works in both test and live mode. The refund is initiated with the payment provider immediately when supported.",
        "operationId": "createRefund",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique key to ensure idempotent requests (1-64 chars, alphanumeric with - and _)",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[A-Za-z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateRefundRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Refund created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RefundResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Refunds" ],
        "summary": "List refunds",
        "operationId": "listRefunds",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of refunds",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedRefundResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/refunds/{id}": {
      "get": {
        "tags": [ "Refunds" ],
        "summary": "Get a refund",
        "operationId": "getRefund",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Refund details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RefundResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/payouts": {
      "post": {
        "tags": [ "Payouts" ],
        "summary": "Create a payout",
        "description": "Sends money to a bank account or mobile wallet.",
        "operationId": "createPayout",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique key to ensure idempotent requests (1-64 chars, alphanumeric with - and _)",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[A-Za-z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreatePayoutRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payout created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PayoutResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Payouts" ],
        "summary": "List payouts",
        "operationId": "listPayouts",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of payouts",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedPayoutResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/payouts/{id}": {
      "get": {
        "tags": [ "Payouts" ],
        "summary": "Get a payout",
        "operationId": "getPayout",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Payout details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PayoutResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/payouts/{id}/cancel": {
      "post": {
        "tags": [ "Payouts" ],
        "summary": "Cancel a pending payout",
        "description": "Only pending payouts can be cancelled.",
        "operationId": "cancelPayout",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Payout cancelled",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PayoutResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/api-keys": {
      "post": {
        "tags": [ "API Keys" ],
        "summary": "Create an API key",
        "description": "Creates a new API key. Accepts either JWT or API key authentication. The raw key is returned only once in the response.",
        "operationId": "createApiKey",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "JwtAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateApiKeyRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "API key created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApiKeyCreatedResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "API Keys" ],
        "summary": "List API keys",
        "description": "Lists all API keys for the authenticated merchant. Accepts either JWT or API key authentication.",
        "operationId": "listApiKeys",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "JwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of API keys",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/ApiKeyResponse" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/api-keys/{id}/revoke": {
      "post": {
        "tags": [ "API Keys" ],
        "summary": "Revoke an API key",
        "description": "Permanently revokes an API key. Accepts either JWT or API key authentication. This cannot be undone.",
        "operationId": "revokeApiKey",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "JwtAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "API key revoked",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ApiKeyResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/balance": {
      "get": {
        "tags": [ "Balance" ],
        "summary": "Get balance",
        "description": "Returns the current available and pending balance.",
        "operationId": "getBalance",
        "responses": {
          "200": {
            "description": "Account balance",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/BalanceResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/balance/transactions": {
      "get": {
        "tags": [ "Balance" ],
        "summary": "List balance transactions",
        "description": "Returns a paginated list of balance transactions (ledger entries).",
        "operationId": "listBalanceTransactions",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of transactions",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedTransactionResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/payment-links": {
      "post": {
        "tags": [ "Payment Links" ],
        "summary": "Create a payment link",
        "description": "Creates a new no-code payment page for receiving payments.",
        "operationId": "createPaymentLink",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreatePaymentLinkRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment link created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentLinkResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Payment Links" ],
        "summary": "List payment links",
        "operationId": "listPaymentLinks",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "status",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/PaymentLinkStatus" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of payment links",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedPaymentLinkResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/payment-links/{id}": {
      "get": {
        "tags": [ "Payment Links" ],
        "summary": "Get a payment link",
        "operationId": "getPaymentLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment link details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentLinkResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": [ "Payment Links" ],
        "summary": "Update a payment link",
        "operationId": "updatePaymentLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdatePaymentLinkRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment link updated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentLinkResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/payment-links/{id}/pause": {
      "post": {
        "tags": [ "Payment Links" ],
        "summary": "Pause a payment link",
        "description": "Pauses an active payment link, temporarily preventing new payments.",
        "operationId": "pausePaymentLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment link paused",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentLinkResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/payment-links/{id}/activate": {
      "post": {
        "tags": [ "Payment Links" ],
        "summary": "Activate a payment link",
        "description": "Activates a draft or paused payment link.",
        "operationId": "activatePaymentLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment link activated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentLinkResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/payment-links/{id}/close": {
      "post": {
        "tags": [ "Payment Links" ],
        "summary": "Close a payment link",
        "description": "Permanently closes a payment link. Cannot be undone.",
        "operationId": "closePaymentLink",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Payment link closed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaymentLinkResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/pay/{slug}": {
      "get": {
        "tags": [ "Payment Links (Public)" ],
        "summary": "Get public payment link metadata",
        "description": "Returns public-facing information about a payment link. No authentication required.",
        "operationId": "getPublicPaymentLink",
        "security": [],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Public payment link details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PublicPaymentLinkResponse" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "post": {
        "tags": [ "Payment Links (Public)" ],
        "summary": "Make a payment on a payment link",
        "description": "Submits a payment against a public payment link. No authentication required. An optional Idempotency-Key header prevents duplicate charges on payer retries.",
        "operationId": "makeLinkPayment",
        "security": [],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional idempotency key (1-64 chars) to prevent duplicate charges",
            "schema": { "type": "string", "minLength": 1, "maxLength": 64 }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/MakeLinkPaymentRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment submitted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/LinkPaymentResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/embed/pay": {
      "post": {
        "tags": [ "Payment Links (Public)" ],
        "summary": "Embed payment",
        "description": "Submits a payment from an embedded widget. Requires a public API key. An optional Idempotency-Key header prevents duplicate charges.",
        "operationId": "embedPayment",
        "security": [
          {
            "PublicKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Optional idempotency key (1-64 chars) to prevent duplicate charges",
            "schema": { "type": "string", "minLength": 1, "maxLength": 64 }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/EmbedPaymentRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Payment submitted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/LinkPaymentResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/webhook-endpoints": {
      "post": {
        "tags": [ "Webhook Endpoints" ],
        "summary": "Create a webhook endpoint",
        "description": "Registers a new URL to receive webhook event notifications.",
        "operationId": "createWebhookEndpoint",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateEndpointRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook endpoint created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EndpointResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Webhook Endpoints" ],
        "summary": "List webhook endpoints",
        "operationId": "listWebhookEndpoints",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of webhook endpoints",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedEndpointResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/webhook-endpoints/{id}": {
      "get": {
        "tags": [ "Webhook Endpoints" ],
        "summary": "Get a webhook endpoint",
        "operationId": "getWebhookEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook endpoint details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EndpointResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "put": {
        "tags": [ "Webhook Endpoints" ],
        "summary": "Update a webhook endpoint",
        "operationId": "updateWebhookEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdateEndpointRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook endpoint updated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EndpointResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "tags": [ "Webhook Endpoints" ],
        "summary": "Delete a webhook endpoint",
        "operationId": "deleteWebhookEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "204": { "description": "Webhook endpoint deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/allowed-origins": {
      "post": {
        "tags": [ "Allowed Origins" ],
        "summary": "Add an allowed origin",
        "description": "Registers a CORS origin for embedded widget access.",
        "operationId": "addAllowedOrigin",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/AddOriginRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Origin added",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AllowedOriginResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Allowed Origins" ],
        "summary": "List allowed origins",
        "operationId": "listAllowedOrigins",
        "responses": {
          "200": {
            "description": "List of allowed origins",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/AllowedOriginResponse" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/allowed-origins/{id}": {
      "delete": {
        "tags": [ "Allowed Origins" ],
        "summary": "Delete an allowed origin",
        "operationId": "deleteAllowedOrigin",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "204": { "description": "Origin deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/tax-rates": {
      "post": {
        "tags": [ "Tax Rates" ],
        "summary": "Create a tax rate",
        "description": "Creates a new tax rate for the authenticated merchant.",
        "operationId": "createTaxRate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateTaxRateRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Tax rate created",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TaxRateResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "get": {
        "tags": [ "Tax Rates" ],
        "summary": "List tax rates",
        "operationId": "listTaxRates",
        "parameters": [
          { "$ref": "#/components/parameters/PageParam" },
          { "$ref": "#/components/parameters/PerPageParam" },
          {
            "name": "active",
            "in": "query",
            "description": "Filter by active status",
            "schema": { "type": "boolean" }
          },
          {
            "name": "inclusive",
            "in": "query",
            "description": "Filter by inclusive flag",
            "schema": { "type": "boolean" }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of tax rates",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedTaxRateResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/tax-rates/{id}": {
      "get": {
        "tags": [ "Tax Rates" ],
        "summary": "Get a tax rate",
        "operationId": "getTaxRate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Tax rate details",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TaxRateResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "put": {
        "tags": [ "Tax Rates" ],
        "summary": "Update a tax rate",
        "operationId": "updateTaxRate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdateTaxRateRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tax rate updated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TaxRateResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/tax-rates/{id}/archive": {
      "post": {
        "tags": [ "Tax Rates" ],
        "summary": "Archive a tax rate",
        "operationId": "archiveTaxRate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Tax rate archived",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TaxRateResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/merchants/signup": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Create a merchant account",
        "description": "Registers a new unverified merchant and sends a verification code via email. The account must be verified before login is allowed.",
        "operationId": "merchantSignup",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SignupRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Merchant created, verification code sent",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MessageResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "409": {
            "description": "Email already registered",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/v1/merchants/verify": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Verify merchant account",
        "description": "Verifies a merchant account using a 6-digit code and returns access + refresh tokens. Sets an HttpOnly fingerprint cookie (`__Secure-Fpr` or `Fpr`) that binds the JWT to this browser session.",
        "operationId": "verifyMerchantAccount",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/VerifyAccountRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account verified, tokens returned. Sets `__Secure-Fpr` (HTTPS) or `Fpr` (dev) HttpOnly cookie.",
            "headers": {
              "Set-Cookie": {
                "description": "Session fingerprint cookie (`__Secure-Fpr` or `Fpr`). HttpOnly, SameSite=Strict (prod) or Lax (dev). Required for all subsequent JWT-authenticated requests.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AuthResponse" }
              }
            }
          },
          "400": {
            "description": "Account already verified or validation error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "401": {
            "description": "Invalid or expired verification code",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/v1/merchants/login": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Authenticate a merchant",
        "description": "Authenticates a verified merchant by email and password, returning access and refresh tokens. Sets an HttpOnly fingerprint cookie that binds the JWT to this browser session.",
        "operationId": "merchantLogin",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/LoginRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Authentication successful. Sets `__Secure-Fpr` (HTTPS) or `Fpr` (dev) HttpOnly cookie.",
            "headers": {
              "Set-Cookie": {
                "description": "Session fingerprint cookie (`__Secure-Fpr` or `Fpr`). HttpOnly, SameSite=Strict (prod) or Lax (dev). Required for all subsequent JWT-authenticated requests.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AuthResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": {
            "description": "Invalid email or password",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "403": {
            "description": "Account suspended or not verified",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/v1/merchants/refresh": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Refresh tokens (full rotation)",
        "description": "Performs full token rotation: validates the refresh token and fingerprint cookie, revokes the old refresh token, and returns new access + refresh tokens with a new fingerprint cookie. Requires the `__Secure-Fpr` (or `Fpr` in dev) cookie from the original login/verify.",
        "operationId": "refreshToken",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/RefreshTokenRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New access + refresh tokens. Sets a new fingerprint cookie replacing the previous one.",
            "headers": {
              "Set-Cookie": {
                "description": "New session fingerprint cookie (`__Secure-Fpr` or `Fpr`). Replaces the previous cookie. Required for subsequent requests.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RefreshResponse" }
              }
            }
          },
          "401": {
            "description": "Invalid, expired, or revoked refresh token",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/v1/merchants/send-verification-code": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Send verification code",
        "description": "Sends a verification code for signup (resend) or password reset. Always returns the same response regardless of email existence (anti-enumeration).",
        "operationId": "sendVerificationCode",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SendVerificationCodeRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification code sent (or silently ignored)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MessageResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/v1/merchants/forgot-password": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Request password reset code",
        "description": "Initiates the password reset flow. Always returns the same response regardless of email existence (anti-enumeration).",
        "operationId": "forgotPassword",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ForgotPasswordRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password reset code sent (or silently ignored)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MessageResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/v1/merchants/reset-password": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Reset password",
        "description": "Resets a merchant's password using a verification code. Revokes all existing refresh tokens.",
        "operationId": "resetPassword",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ResetPasswordRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password reset successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MessageResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": {
            "description": "Invalid or expired verification code",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/v1/merchants/me": {
      "get": {
        "tags": [ "Merchants" ],
        "summary": "Get merchant profile",
        "description": "Returns the authenticated merchant's profile. Requires JWT access token and fingerprint cookie.",
        "operationId": "getMerchantProfile",
        "security": [
          {
            "JwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Merchant profile",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MerchantResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/merchants/change-password/request-code": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Request password change code",
        "description": "Generates a verification code for changing the password. Requires JWT access token and fingerprint cookie.",
        "operationId": "requestPasswordChangeCode",
        "security": [
          {
            "JwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Verification code generated",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MessageResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/v1/merchants/change-password": {
      "post": {
        "tags": [ "Merchants" ],
        "summary": "Change password",
        "description": "Changes the authenticated merchant's password using a verification code. Revokes all existing refresh tokens. Requires JWT access token and fingerprint cookie.",
        "operationId": "changePassword",
        "security": [
          {
            "JwtAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ChangePasswordRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password changed successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/MessageResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": {
            "description": "Invalid or expired verification code",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key authentication. Use `sk_test_*` for test mode, `sk_live_*` for live mode."
      },
      "JwtAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "JWT token obtained from merchant signup or login." },
      "PublicKeyAuth": { "type": "http", "scheme": "bearer", "description": "Public API key for embedded widgets. Use `pk_test_*` or `pk_live_*`." }
    },
    "parameters": {
      "PageParam": {
        "name": "page",
        "in": "query",
        "description": "Page number (1-indexed)",
        "schema": { "type": "integer", "default": 1, "minimum": 1 }
      },
      "PerPageParam": {
        "name": "per_page",
        "in": "query",
        "description": "Items per page",
        "schema": { "type": "integer", "default": 20, "minimum": 1, "maximum": 100 }
      },
      "ModeParam": {
        "name": "mode",
        "in": "query",
        "description": "Environment mode for JWT-authenticated requests. Defaults to live. Set to 'test' to access test data. Ignored for API key authentication (mode is derived from the key prefix). Can also be set via X-Mode header.",
        "schema": { "type": "string", "enum": [ "live", "test" ], "default": "live" }
      }
    },
    "responses": {
      "ValidationError": {
        "description": "Validation error",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "Unauthorized": {
        "description": "Invalid or missing API key",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": [ "error" ],
        "properties": {
          "error": {
            "type": "object",
            "required": [ "code", "message" ],
            "properties": {
              "code": { "type": "string", "example": "validation_failed" },
              "message": { "type": "string", "example": "Invalid request" },
              "field": { "type": "string", "example": "amount" },
              "details": { "type": "string" }
            }
          }
        }
      },
      "Money": {
        "type": "object",
        "required": [ "amount", "currency" ],
        "properties": {
          "amount": { "type": "number", "example": 50.0 },
          "currency": { "type": "string", "example": "GHS" }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "required": [ "page", "per_page", "total", "total_pages" ],
        "properties": {
          "page": { "type": "integer", "example": 1 },
          "per_page": { "type": "integer", "example": 20 },
          "total": { "type": "integer", "example": 45 },
          "total_pages": { "type": "integer", "example": 3 }
        }
      },
      "PaymentStatus": {
        "type": "string",
        "enum": [ "pending", "processing", "successful", "failed", "cancelled", "refunded" ]
      },
      "PaymentMethod": {
        "type": "string",
        "enum": [ "mtn_momo", "telecel_cash", "airteltigo_money", "bank_transfer", "card" ]
      },
      "InitiatePaymentRequest": {
        "type": "object",
        "required": [ "amount", "payment_method" ],
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 1,
            "maximum": 50000,
            "example": 100.0,
            "description": "Amount in major units (e.g., 100.00 for GHS 100)"
          },
          "currency": {
            "type": "string",
            "default": "GHS",
            "example": "GHS",
            "enum": [ "GHS" ],
            "description": "Currently supported currencies: [\"GHS\"]"
          },
          "payment_method": {
            "type": "string",
            "example": "mtn_momo",
            "description": "One of: mtn_momo, telecel_cash, airteltigo_money, bank_transfer, card"
          },
          "customer_phone": { "type": "string", "example": "233241234567", "description": "Required for mobile money payments. Validated against the merchant's country. Currently supported countries: [\"GH\"]" },
          "customer_email": { "type": "string", "format": "email", "example": "user@example.com" },
          "description": { "type": "string", "maxLength": 255, "example": "Order #12345" },
          "metadata": { "type": "object", "additionalProperties": true },
          "callback_url": { "type": "string", "format": "uri", "example": "https://merchant.com/webhooks/payment" }
        }
      },
      "PaymentResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "reference": { "type": "string", "example": "KZ-20240115-ABC123" },
          "amount": { "$ref": "#/components/schemas/Money" },
          "status": { "$ref": "#/components/schemas/PaymentStatus" },
          "payment_method": { "$ref": "#/components/schemas/PaymentMethod" },
          "customer_phone": { "type": "string", "example": "233***567", "description": "Masked phone number" },
          "customer_email": { "type": "string", "example": "us***@example.com", "description": "Masked email" },
          "checkout_url": {
            "type": "string",
            "format": "uri",
            "description": "URL for customer to complete payment (if applicable). Persisted and returned again on idempotent replay."
          },
          "provider_reference": { "type": "string" },
          "fee": { "$ref": "#/components/schemas/Money" },
          "metadata": { "type": "object", "additionalProperties": true },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedPaymentResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/PaymentResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "CreateCustomerRequest": {
        "type": "object",
        "required": [ "name" ],
        "properties": {
          "name": { "type": "string", "minLength": 2, "maxLength": 100, "example": "Kwame Asante" },
          "email": { "type": "string", "format": "email", "example": "kwame@example.com" },
          "phone": { "type": "string", "example": "233241234567", "description": "Customer phone number. Validated against the merchant's country. Currently supported countries: [\"GH\"]" },
          "customer_type": {
            "type": "string",
            "enum": [ "individual", "business" ],
            "default": "individual"
          },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "UpdateCustomerRequest": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "minLength": 2, "maxLength": 100 },
          "email": { "type": "string", "format": "email" },
          "phone": { "type": "string", "description": "Customer phone number. Validated against the merchant's country. Currently supported countries: [\"GH\"]" },
          "customer_type": {
            "type": "string",
            "enum": [ "individual", "business" ]
          },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "CustomerResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string", "example": "Kwame Asante" },
          "email": { "type": "string", "example": "kw***@example.com" },
          "phone": { "type": "string", "example": "233***567" },
          "status": {
            "type": "string",
            "enum": [ "active", "suspended" ]
          },
          "customer_type": {
            "type": "string",
            "enum": [ "individual", "business" ]
          },
          "metadata": { "type": "object", "additionalProperties": true },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedCustomerResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/CustomerResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "CreatePlanRequest": {
        "type": "object",
        "required": [ "name", "billing_interval" ],
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100, "example": "Premium Monthly" },
          "billing_interval": { "$ref": "#/components/schemas/BillingInterval" },
          "trial_days": { "type": "integer", "minimum": 0, "maximum": 90, "default": 0, "description": "Trial period in days (0 = no trial)" },
          "description": { "type": "string", "maxLength": 255 },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "UpdatePlanRequest": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100 },
          "description": { "type": "string", "maxLength": 255 },
          "active": { "type": "boolean", "description": "Set to false to deactivate the plan" },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "PlanResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string", "example": "Premium Monthly" },
          "billing_interval": { "$ref": "#/components/schemas/BillingInterval" },
          "trial_days": { "type": "integer", "example": 14 },
          "description": { "type": "string" },
          "active": { "type": "boolean" },
          "metadata": { "type": "object", "additionalProperties": true },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedPlanResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/PlanResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "SubscriptionStatus": {
        "type": "string",
        "enum": [ "trialing", "active", "paused", "past_due", "cancelled", "expired" ]
      },
      "BillingInterval": {
        "type": "string",
        "enum": [ "daily", "weekly", "monthly", "quarterly", "yearly" ]
      },
      "CreateSubscriptionRequest": {
        "type": "object",
        "required": [ "customer_id", "plan_id", "payment_method" ],
        "properties": {
          "customer_id": { "type": "string", "format": "uuid" },
          "plan_id": { "type": "string", "format": "uuid", "description": "ID of an active plan that defines billing terms" },
          "amount": { "type": "number", "minimum": 1, "maximum": 50000, "example": 50.0, "nullable": true, "description": "Inline subscription amount. Provide either amount or price_id." },
          "currency": {
            "type": "string",
            "default": "GHS",
            "enum": [ "GHS" ],
            "description": "Currently supported currencies: [\"GHS\"]. When price_id is set, this must match the selected price currency."
          },
          "payment_method": {
            "type": "string",
            "example": "card",
            "description": "Must support subscriptions (card, bank_transfer). Mobile money is not supported for recurring billing."
          },
          "customer_phone": { "type": "string", "example": "233241234567", "description": "Customer phone number. Validated against the merchant's country. Currently supported countries: [\"GH\"]" },
          "customer_email": { "type": "string", "format": "email" },
          "description": { "type": "string", "maxLength": 255 },
          "metadata": { "type": "object", "additionalProperties": true },
          "price_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Price ID for price-based subscriptions. Provide either price_id or amount." },
          "quantity": { "type": "integer", "nullable": true, "default": 1, "description": "Number of units (used with price_id)" }
        }
      },
      "DowngradeRequest": {
        "type": "object",
        "required": [ "plan_id" ],
        "properties": {
          "plan_id": { "type": "string", "format": "uuid", "description": "The plan to switch to at period end" },
          "price_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Price ID for a price-based downgrade. The selected price currency must match the subscription currency." },
          "amount": { "type": "number", "minimum": 1, "maximum": 50000, "example": 25.0, "nullable": true, "description": "New amount after downgrade in the subscription's existing currency. Provide either amount or price_id." }
        }
      },
      "SubscriptionResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "reference": { "type": "string", "example": "SUB-20240115-ABC123" },
          "customer_id": { "type": "string", "format": "uuid" },
          "plan_id": { "type": "string", "format": "uuid", "description": "ID of the plan this subscription was created from" },
          "plan_name": { "type": "string", "example": "Premium Plan", "description": "Denormalized plan name (snapshot at creation time)" },
          "amount": { "$ref": "#/components/schemas/Money" },
          "billing_interval": { "$ref": "#/components/schemas/BillingInterval" },
          "status": { "$ref": "#/components/schemas/SubscriptionStatus" },
          "payment_method": { "type": "string" },
          "customer_phone": { "type": "string", "example": "233***567" },
          "customer_email": { "type": "string", "example": "us***@example.com" },
          "description": { "type": "string" },
          "metadata": { "type": "object", "additionalProperties": true },
          "trial_end": { "type": "string", "format": "date-time" },
          "current_period_start": { "type": "string", "format": "date-time" },
          "current_period_end": { "type": "string", "format": "date-time" },
          "cancelled_at": { "type": "string", "format": "date-time" },
          "cancel_at": { "type": "string", "format": "date-time", "description": "Scheduled cancellation time. Omitted when not scheduled." },
          "pending_change": {
            "description": "Pending plan/amount change scheduled for period end. Omitted when nothing is scheduled.",
            "allOf": [
              { "$ref": "#/components/schemas/PendingChangeResponse" }
            ]
          },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "price_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Price ID (if created from a price)" },
          "quantity": { "type": "integer", "nullable": true },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" }
        }
      },
      "PendingChangeResponse": {
        "type": "object",
        "properties": {
          "plan_id": { "type": "string", "format": "uuid" },
          "amount": { "$ref": "#/components/schemas/Money" },
          "effective_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedSubscriptionResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SubscriptionResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "InvoiceStatus": {
        "type": "string",
        "enum": [ "draft", "open", "paid", "void", "uncollectible" ]
      },
      "LineItemRequest": {
        "type": "object",
        "required": [ "description", "quantity", "unit_amount" ],
        "properties": {
          "description": { "type": "string", "minLength": 1, "maxLength": 255, "example": "Monthly subscription fee", "nullable": true },
          "quantity": { "type": "integer", "minimum": 1, "example": 1 },
          "unit_amount": { "type": "number", "exclusiveMinimum": 0, "example": 50.0, "description": "Unit price in major units", "nullable": true },
          "tax_rate_ids": {
            "type": "array",
            "items": { "type": "string", "format": "uuid" },
            "description": "Tax rates to apply to this line item"
          },
          "price_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Price ID to auto-fill description and unit_amount" }
        }
      },
      "CreateInvoiceRequest": {
        "type": "object",
        "required": [ "customer_id", "line_items" ],
        "properties": {
          "customer_id": { "type": "string", "format": "uuid" },
          "subscription_id": { "type": "string", "format": "uuid", "description": "Link to a subscription (for recurring invoices)" },
          "currency": {
            "type": "string",
            "default": "GHS",
            "enum": [ "GHS" ],
            "description": "Currently supported currencies: [\"GHS\"]. When any line item uses price_id, this must match the selected price currency."
          },
          "line_items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": { "$ref": "#/components/schemas/LineItemRequest" }
          },
          "due_days": { "type": "integer", "minimum": 1, "maximum": 365, "example": 30, "description": "Number of days until due" },
          "memo": { "type": "string", "maxLength": 500, "example": "Thank you for your business" },
          "default_tax_rate_ids": {
            "type": "array",
            "items": { "type": "string", "format": "uuid" },
            "description": "Tax rates applied to all line items by default"
          },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "LineItemResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "description": { "type": "string", "nullable": true },
          "quantity": { "type": "integer" },
          "unit_amount": { "type": "number", "description": "Unit price in major units", "nullable": true },
          "amount": { "type": "number", "description": "Total amount (quantity x unit_amount)" },
          "taxes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/LineItemTaxResponse" }
          },
          "price_id": { "type": "string", "format": "uuid", "nullable": true },
          "product_id": { "type": "string", "format": "uuid", "nullable": true },
          "product_name": { "type": "string", "nullable": true }
        }
      },
      "LineItemTaxResponse": {
        "type": "object",
        "properties": {
          "tax_rate_id": { "type": "string", "format": "uuid" },
          "display_name": { "type": "string" },
          "percentage": { "type": "number" },
          "inclusive": { "type": "boolean" },
          "taxable_amount": { "type": "number" },
          "tax_amount": { "type": "number" }
        }
      },
      "TaxBreakdownResponse": {
        "type": "object",
        "properties": {
          "tax_rate_id": { "type": "string", "format": "uuid" },
          "display_name": { "type": "string" },
          "percentage": { "type": "number" },
          "inclusive": { "type": "boolean" },
          "total_taxable_amount": { "type": "number" },
          "total_tax_amount": { "type": "number" }
        }
      },
      "InvoiceResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "reference": { "type": "string", "example": "INV-20240115-ABC123" },
          "customer_id": { "type": "string", "format": "uuid" },
          "subscription_id": { "type": "string", "format": "uuid" },
          "status": { "$ref": "#/components/schemas/InvoiceStatus" },
          "subtotal": { "$ref": "#/components/schemas/Money" },
          "tax": { "$ref": "#/components/schemas/Money" },
          "total": { "$ref": "#/components/schemas/Money" },
          "line_items": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/LineItemResponse" }
          },
          "tax_breakdown": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TaxBreakdownResponse" }
          },
          "customer_email": { "type": "string", "example": "us***@example.com" },
          "memo": { "type": "string" },
          "metadata": { "type": "object", "additionalProperties": true },
          "due_date": { "type": "string", "format": "date-time" },
          "paid_at": { "type": "string", "format": "date-time" },
          "voided_at": { "type": "string", "format": "date-time" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedInvoiceResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/InvoiceResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "CheckoutType": {
        "type": "string",
        "enum": [ "payment", "subscription" ]
      },
      "CheckoutStatus": {
        "type": "string",
        "enum": [ "open", "complete", "expired" ]
      },
      "CreateCheckoutRequest": {
        "type": "object",
        "required": [ "checkout_type", "success_url", "failure_url", "amount", "currency", "payment_method" ],
        "properties": {
          "checkout_type": { "$ref": "#/components/schemas/CheckoutType" },
          "success_url": { "type": "string", "format": "uri", "description": "URL to redirect after successful payment" },
          "failure_url": { "type": "string", "format": "uri", "description": "URL to redirect after failed or cancelled payment" },
          "amount": { "type": "number", "minimum": 1, "example": 100.0, "description": "Amount in major units", "nullable": true },
          "currency": {
            "type": "string",
            "example": "GHS",
            "default": "GHS",
            "enum": [ "GHS" ],
            "description": "Currently supported currencies: [\"GHS\"]. When price_id is set, this must match the selected price currency."
          },
          "payment_method": { "type": "string", "example": "mtn_momo" },
          "customer_phone": { "type": "string", "example": "233241234567", "description": "Customer phone number. Validated against the merchant's country. Currently supported countries: [\"GH\"]" },
          "customer_email": { "type": "string", "format": "email" },
          "description": { "type": "string", "maxLength": 255 },
          "metadata": { "type": "object", "additionalProperties": true },
          "plan_id": {
            "type": "string",
            "format": "uuid",
            "description": "Plan ID (required for subscription checkouts). References an active plan."
          },
          "customer_id": { "type": "string", "format": "uuid", "description": "Existing customer ID (required for subscription checkouts)" },
          "price_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Price ID for price-based checkouts" },
          "quantity": { "type": "integer", "nullable": true, "default": 1, "description": "Number of units (used with price_id)" }
        }
      },
      "CheckoutResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "reference": { "type": "string" },
          "checkout_type": { "$ref": "#/components/schemas/CheckoutType" },
          "status": { "$ref": "#/components/schemas/CheckoutStatus" },
          "success_url": { "type": "string", "format": "uri" },
          "failure_url": { "type": "string", "format": "uri" },
          "amount": { "$ref": "#/components/schemas/Money" },
          "payment_method": { "type": "string" },
          "customer_phone": { "type": "string" },
          "customer_email": { "type": "string" },
          "description": { "type": "string" },
          "metadata": { "type": "object", "additionalProperties": true },
          "plan_id": { "type": "string", "format": "uuid", "description": "Plan ID (subscription checkouts)" },
          "customer_id": { "type": "string", "format": "uuid" },
          "checkout_url": { "type": "string", "format": "uri", "description": "URL to redirect the customer to complete checkout" },
          "payment_id": { "type": "string", "format": "uuid", "description": "Associated payment ID (after completion)" },
          "subscription_id": { "type": "string", "format": "uuid", "description": "Associated subscription ID (after completion)" },
          "expires_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": "string", "format": "date-time" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "price_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Price ID (if created from a price)" },
          "quantity": { "type": "integer", "nullable": true },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" }
        }
      },
      "PaginatedCheckoutResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/CheckoutResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "RefundStatus": {
        "type": "string",
        "enum": [ "pending", "processing", "succeeded", "failed", "canceled" ]
      },
      "CreateRefundRequest": {
        "type": "object",
        "required": [ "payment_id" ],
        "properties": {
          "payment_id": { "type": "string", "description": "ID of the payment to refund" },
          "amount": { "type": "integer", "description": "Refund amount in minor units (pesewas). Omit for full refund." },
          "reason": { "type": "string", "description": "Reason for the refund" }
        }
      },
      "RefundResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "payment_id": { "type": "string", "format": "uuid" },
          "amount": { "type": "integer", "description": "Refund amount in minor units (pesewas)" },
          "currency": { "type": "string", "example": "GHS" },
          "status": { "$ref": "#/components/schemas/RefundStatus" },
          "reason": { "type": "string" },
          "reference": { "type": "string" },
          "provider_refund_id": { "type": "string", "description": "Provider-assigned refund identifier" },
          "provider_name": { "type": "string", "description": "Name of the payment provider handling the refund" },
          "failure_reason": { "type": "string", "description": "Provider-reported failure reason" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": "string", "format": "date-time" },
          "canceled_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedRefundResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/RefundResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "PayoutStatus": {
        "type": "string",
        "enum": [ "pending", "processing", "paid", "failed", "cancelled" ]
      },
      "CreatePayoutRequest": {
        "type": "object",
        "required": [ "amount", "destination_type", "destination_details" ],
        "properties": {
          "amount": { "type": "integer", "minimum": 1, "description": "Payout amount in minor units (pesewas)" },
          "destination_type": { "type": "string", "description": "Destination type (e.g., mtn_momo, bank_account)" },
          "destination_details": {
            "type": "object",
            "additionalProperties": true,
            "description": "Destination-specific details (account number, phone, etc.)"
          },
          "description": { "type": "string", "description": "Optional description for the payout" }
        }
      },
      "PayoutResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "amount": { "type": "integer", "description": "Payout amount in minor units (pesewas)" },
          "fee": { "type": "integer", "description": "Payout fee in minor units (pesewas)" },
          "currency": { "type": "string", "example": "GHS" },
          "status": { "$ref": "#/components/schemas/PayoutStatus" },
          "destination_type": { "type": "string" },
          "destination_details": { "type": "object", "additionalProperties": true },
          "reference": { "type": "string" },
          "description": { "type": "string" },
          "provider_payout_id": { "type": "string", "description": "Provider-assigned payout identifier" },
          "provider_name": { "type": "string", "description": "Name of the payment provider handling the payout" },
          "failure_reason": { "type": "string", "description": "Provider-reported failure reason" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedPayoutResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/PayoutResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "ApiKeyType": {
        "type": "string",
        "enum": [ "secret", "public" ],
        "description": "Key type. Restricted keys (rk_*) are not yet available."
      },
      "CreateApiKeyRequest": {
        "type": "object",
        "required": [ "name", "key_type" ],
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Human-readable name for the key" },
          "key_type": { "$ref": "#/components/schemas/ApiKeyType" },
          "is_test": { "type": "boolean", "default": false, "description": "Whether this is a test-mode key" }
        }
      },
      "ApiKeyCreatedResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "key_type": { "$ref": "#/components/schemas/ApiKeyType" },
          "is_test": { "type": "boolean" },
          "key": { "type": "string", "description": "The raw API key. Shown only once at creation time." },
          "key_prefix": { "type": "string", "description": "Key prefix for identification (e.g., sk_test_)" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "ApiKeyResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "key_type": { "$ref": "#/components/schemas/ApiKeyType" },
          "key_hint": { "type": "string", "description": "Last 4 characters of the key for identification" },
          "is_test": { "type": "boolean" },
          "enabled": { "type": "boolean" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "last_used_at": { "type": "string", "format": "date-time" },
          "created_at": { "type": "string", "format": "date-time" },
          "revoked_at": { "type": "string", "format": "date-time" }
        }
      },
      "BalanceResponse": {
        "type": "object",
        "required": [ "available", "pending", "currency" ],
        "properties": {
          "available": { "type": "integer", "description": "Available balance in minor units (pesewas)" },
          "pending": { "type": "integer", "description": "Pending balance in minor units (pesewas)" },
          "currency": { "type": "string", "example": "GHS" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" }
        }
      },
      "TransactionResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "entry_type": { "type": "string", "description": "Type of ledger entry" },
          "direction": {
            "type": "string",
            "enum": [ "in", "out" ],
            "description": "Direction of the transaction"
          },
          "amount": { "type": "integer", "description": "Amount in minor units (pesewas)" },
          "currency": { "type": "string", "example": "GHS" },
          "description": { "type": "string" },
          "reference_type": { "type": "string", "description": "Type of the referenced entity (payment, payout, refund, etc.)" },
          "reference_id": { "type": "string", "format": "uuid", "description": "ID of the referenced entity" },
          "available_at": { "type": "string", "format": "date-time", "description": "When the funds become available" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedTransactionResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TransactionResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "PaymentLinkStatus": {
        "type": "string",
        "enum": [ "draft", "active", "paused", "closed" ]
      },
      "FeeAbsorption": {
        "type": "string",
        "enum": [ "payer_pays", "deducted_from_payment" ]
      },
      "PayoutSchedule": {
        "type": "string",
        "enum": [ "instant", "daily", "manual" ]
      },
      "CreatePaymentLinkRequest": {
        "type": "object",
        "required": [ "title", "payout_destination_type", "payout_destination_details" ],
        "properties": {
          "title": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Title of the payment link page" },
          "description": { "type": "string", "description": "Description shown to payers" },
          "target_amount_minor_units": { "type": "integer", "description": "Fundraising target in minor units (pesewas)" },
          "slug": { "type": "string", "minLength": 3, "maxLength": 80, "description": "Custom URL slug. Auto-generated if omitted." },
          "payout_destination_type": { "type": "string", "description": "Destination type for payouts (e.g., mtn_momo, bank_account)" },
          "payout_destination_details": { "type": "object", "additionalProperties": true, "description": "Destination-specific details" },
          "payout_schedule": { "$ref": "#/components/schemas/PayoutSchedule" },
          "fee_absorption": { "$ref": "#/components/schemas/FeeAbsorption" },
          "min_amount_minor_units": { "type": "integer", "description": "Minimum payment amount in minor units" },
          "max_amount_minor_units": { "type": "integer", "description": "Maximum payment amount in minor units" },
          "thank_you_message": { "type": "string", "description": "Message shown after successful payment" },
          "metadata": { "type": "object", "additionalProperties": true },
          "price_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Price ID for price-based payment links" },
          "quantity": { "type": "integer", "nullable": true, "default": 1, "description": "Number of units (used with price_id)" }
        }
      },
      "UpdatePaymentLinkRequest": {
        "type": "object",
        "properties": {
          "title": { "type": "string", "minLength": 1, "maxLength": 200 },
          "description": { "type": "string" },
          "target_amount_minor_units": { "type": "integer" },
          "payout_schedule": { "$ref": "#/components/schemas/PayoutSchedule" },
          "fee_absorption": { "$ref": "#/components/schemas/FeeAbsorption" },
          "min_amount_minor_units": { "type": "integer" },
          "max_amount_minor_units": { "type": "integer" },
          "thank_you_message": { "type": "string" },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "PaymentLinkResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "slug": { "type": "string" },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "target_amount": { "$ref": "#/components/schemas/Money" },
          "total_raised": { "$ref": "#/components/schemas/Money" },
          "payment_count": { "type": "integer", "description": "Total number of payments received" },
          "payout_destination_type": { "type": "string" },
          "payout_schedule": { "$ref": "#/components/schemas/PayoutSchedule" },
          "fee_absorption": { "$ref": "#/components/schemas/FeeAbsorption" },
          "status": { "$ref": "#/components/schemas/PaymentLinkStatus" },
          "pay_url": { "type": "string", "format": "uri", "description": "Public URL for payers" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "price_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Price ID (if created from a price)" },
          "quantity": { "type": "integer", "nullable": true },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" }
        }
      },
      "PaginatedPaymentLinkResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/PaymentLinkResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "PublicPaymentLinkResponse": {
        "type": "object",
        "properties": {
          "slug": { "type": "string" },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "target_amount": { "$ref": "#/components/schemas/Money" },
          "total_raised": { "$ref": "#/components/schemas/Money" },
          "payment_count": { "type": "integer" },
          "currency": { "type": "string", "example": "GHS" },
          "fee_absorption": { "$ref": "#/components/schemas/FeeAbsorption" },
          "min_amount": { "$ref": "#/components/schemas/Money" },
          "max_amount": { "$ref": "#/components/schemas/Money" },
          "thank_you_message": { "type": "string" }
        }
      },
      "LinkPaymentStatus": {
        "type": "string",
        "enum": [ "pending", "successful", "failed" ]
      },
      "MakeLinkPaymentRequest": {
        "type": "object",
        "required": [ "amount", "payment_method" ],
        "properties": {
          "amount": { "type": "number", "description": "Payment amount in major units" },
          "payment_method": { "type": "string", "description": "Payment method (e.g., mtn_momo)" },
          "customer_phone": { "type": "string", "description": "Phone number for mobile money payments. Validated against the merchant's country. Currently supported countries: [\"GH\"]" },
          "payer_email": { "type": "string", "format": "email", "maxLength": 200 },
          "payer_name": { "type": "string", "maxLength": 200 },
          "payer_message": { "type": "string", "maxLength": 500 }
        }
      },
      "EmbedPaymentRequest": {
        "type": "object",
        "required": [ "slug", "amount", "payment_method" ],
        "properties": {
          "slug": { "type": "string", "description": "Payment link slug" },
          "amount": { "type": "number", "description": "Payment amount in major units" },
          "payment_method": { "type": "string" },
          "customer_phone": { "type": "string", "description": "Phone number for mobile money payments. Validated against the merchant's country. Currently supported countries: [\"GH\"]" },
          "payer_email": { "type": "string", "format": "email", "maxLength": 200 },
          "payer_name": { "type": "string", "maxLength": 200 },
          "payer_message": { "type": "string", "maxLength": 500 }
        }
      },
      "LinkPaymentResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "link_slug": { "type": "string" },
          "amount": { "$ref": "#/components/schemas/Money" },
          "fee": { "$ref": "#/components/schemas/Money" },
          "net_amount": { "$ref": "#/components/schemas/Money" },
          "status": { "$ref": "#/components/schemas/LinkPaymentStatus" },
          "payer_name": { "type": "string" },
          "checkout_url": {
            "type": "string",
            "format": "uri",
            "description": "URL for payer to complete payment (if applicable). Persisted and returned again on idempotent replay."
          },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "CreateEndpointRequest": {
        "type": "object",
        "required": [ "url", "events" ],
        "properties": {
          "url": { "type": "string", "format": "uri", "description": "URL to receive webhook events" },
          "events": {
            "type": "array",
            "items": { "type": "string" },
            "minItems": 1,
            "description": "List of event types to subscribe to"
          },
          "description": { "type": "string", "description": "Optional description for the endpoint" }
        }
      },
      "UpdateEndpointRequest": {
        "type": "object",
        "properties": {
          "url": { "type": "string", "format": "uri" },
          "events": {
            "type": "array",
            "items": { "type": "string" }
          },
          "enabled": { "type": "boolean" },
          "description": { "type": "string" }
        }
      },
      "EndpointResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "url": { "type": "string", "format": "uri" },
          "events": {
            "type": "array",
            "items": { "type": "string" }
          },
          "enabled": { "type": "boolean" },
          "description": { "type": "string" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedEndpointResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/EndpointResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "AddOriginRequest": {
        "type": "object",
        "required": [ "origin" ],
        "properties": {
          "origin": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Origin URL (e.g., https://example.com)" }
        }
      },
      "AllowedOriginResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "origin": { "type": "string" },
          "verified": { "type": "boolean" },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "MerchantStatus": {
        "type": "string",
        "enum": [ "active", "suspended", "deactivated" ]
      },
      "SignupRequest": {
        "type": "object",
        "required": [ "email", "password", "business_name", "country", "first_name", "last_name", "date_of_birth" ],
        "properties": {
          "email": { "type": "string", "format": "email" },
          "password": { "type": "string", "minLength": 8, "maxLength": 128 },
          "business_name": { "type": "string", "minLength": 1, "maxLength": 255 },
          "country": {
            "type": "string",
            "enum": [ "GH" ],
            "description": "Merchant country. Currently supported countries: [\"GH\"]"
          },
          "first_name": { "type": "string", "minLength": 3, "maxLength": 100 },
          "middle_name": { "type": "string", "minLength": 3, "maxLength": 100 },
          "last_name": { "type": "string", "minLength": 3, "maxLength": 100 },
          "date_of_birth": { "type": "string", "format": "date", "example": "1990-01-15" }
        }
      },
      "LoginRequest": {
        "type": "object",
        "required": [ "email", "password" ],
        "properties": {
          "email": { "type": "string", "format": "email", "description": "Merchant email address" },
          "password": { "type": "string", "minLength": 1, "description": "Merchant password" }
        }
      },
      "MerchantResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "email": { "type": "string", "format": "email" },
          "business_name": { "type": "string" },
          "country": {
            "type": "string",
            "enum": [ "GH" ],
            "description": "Merchant country"
          },
          "first_name": { "type": "string" },
          "middle_name": { "type": "string" },
          "last_name": { "type": "string" },
          "date_of_birth": { "type": "string", "format": "date" },
          "status": { "$ref": "#/components/schemas/MerchantStatus" },
          "verified": { "type": "boolean" },
          "kyc_status": {
            "type": "string",
            "enum": [ "not_submitted", "pending_review", "approved", "rejected", "resubmission_required" ]
          },
          "is_superuser": { "type": "boolean" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "AuthResponse": {
        "type": "object",
        "properties": {
          "access_token": { "type": "string", "description": "JWT access token (1-day TTL) for authenticated requests" },
          "refresh_token": { "type": "string", "description": "JWT refresh token (5-day TTL) for obtaining new access tokens" },
          "merchant": { "$ref": "#/components/schemas/MerchantResponse" }
        }
      },
      "RefreshResponse": {
        "type": "object",
        "properties": {
          "access_token": { "type": "string", "description": "New JWT access token" },
          "refresh_token": { "type": "string", "description": "New JWT refresh token (full rotation — old token is revoked)" }
        }
      },
      "MessageResponse": {
        "type": "object",
        "properties": {
          "message": { "type": "string", "description": "Human-readable status message" }
        }
      },
      "VerifyAccountRequest": {
        "type": "object",
        "required": [ "email", "code" ],
        "properties": {
          "email": { "type": "string", "format": "email", "description": "Merchant email address" },
          "code": { "type": "string", "minLength": 6, "maxLength": 6, "description": "6-digit verification code" }
        }
      },
      "RefreshTokenRequest": {
        "type": "object",
        "required": [ "refresh_token" ],
        "properties": {
          "refresh_token": { "type": "string", "description": "JWT refresh token" }
        }
      },
      "SendVerificationCodeRequest": {
        "type": "object",
        "required": [ "email", "purpose" ],
        "properties": {
          "email": { "type": "string", "format": "email", "description": "Merchant email address" },
          "purpose": {
            "type": "string",
            "enum": [ "signup", "password_reset" ],
            "description": "Purpose of the verification code"
          }
        }
      },
      "ForgotPasswordRequest": {
        "type": "object",
        "required": [ "email" ],
        "properties": {
          "email": { "type": "string", "format": "email", "description": "Merchant email address" }
        }
      },
      "ResetPasswordRequest": {
        "type": "object",
        "required": [ "email", "code", "new_password" ],
        "properties": {
          "email": { "type": "string", "format": "email", "description": "Merchant email address" },
          "code": { "type": "string", "minLength": 6, "maxLength": 6, "description": "6-digit verification code" },
          "new_password": { "type": "string", "minLength": 8, "maxLength": 128, "description": "New password" }
        }
      },
      "ChangePasswordRequest": {
        "type": "object",
        "required": [ "code", "new_password" ],
        "properties": {
          "code": { "type": "string", "minLength": 6, "maxLength": 6, "description": "6-digit verification code" },
          "new_password": { "type": "string", "minLength": 8, "maxLength": 128, "description": "New password" }
        }
      },
      "CreateTaxRateRequest": {
        "type": "object",
        "required": [ "display_name", "percentage" ],
        "properties": {
          "display_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Human-readable name for the tax rate",
            "example": "VAT"
          },
          "description": { "type": "string", "maxLength": 255, "description": "Optional description" },
          "percentage": { "type": "number", "minimum": 0, "maximum": 100, "description": "Tax percentage (e.g. 15 for 15%)", "example": 15 },
          "inclusive": { "type": "boolean", "default": false, "description": "Whether the tax is included in the price" },
          "jurisdiction": { "type": "string", "maxLength": 100, "description": "Tax jurisdiction", "example": "Ghana" }
        }
      },
      "UpdateTaxRateRequest": {
        "type": "object",
        "properties": {
          "display_name": { "type": "string", "minLength": 1, "maxLength": 100 },
          "description": { "type": "string", "maxLength": 255 },
          "percentage": { "type": "number", "minimum": 0, "maximum": 100 },
          "inclusive": { "type": "boolean" },
          "jurisdiction": { "type": "string", "maxLength": 100 }
        }
      },
      "TaxRateResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "merchant_id": { "type": "string", "format": "uuid", "nullable": true },
          "display_name": { "type": "string" },
          "description": { "type": "string", "nullable": true },
          "percentage": { "type": "number", "description": "Tax percentage" },
          "inclusive": { "type": "boolean" },
          "jurisdiction": { "type": "string", "nullable": true },
          "is_system": { "type": "boolean", "description": "Whether this is a system-defined tax rate" },
          "active": { "type": "boolean" },
          "livemode": { "type": "boolean", "nullable": true, "description": "Whether the object exists in live mode or test mode. Null for system-defined tax rates." },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "PaginatedTaxRateResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TaxRateResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "ProductResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "description": { "type": "string", "nullable": true },
          "active": { "type": "boolean" },
          "images": {
            "type": "array",
            "items": { "type": "string" }
          },
          "statement_descriptor": { "type": "string", "nullable": true },
          "unit_label": { "type": "string", "nullable": true },
          "metadata": { "type": "object", "additionalProperties": true, "nullable": true },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "CreateProductRequest": {
        "type": "object",
        "required": [ "name" ],
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100 },
          "description": { "type": "string", "maxLength": 500 },
          "images": {
            "type": "array",
            "items": { "type": "string" },
            "maxItems": 8
          },
          "statement_descriptor": { "type": "string", "maxLength": 22 },
          "unit_label": { "type": "string", "maxLength": 12 },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "UpdateProductRequest": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100 },
          "description": { "type": "string" },
          "active": { "type": "boolean" },
          "images": {
            "type": "array",
            "items": { "type": "string" }
          },
          "statement_descriptor": { "type": "string" },
          "unit_label": { "type": "string" },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "PaginatedProductResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ProductResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "PriceResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "product_id": { "type": "string", "format": "uuid" },
          "active": { "type": "boolean" },
          "currency": { "type": "string" },
          "price_type": {
            "type": "string",
            "enum": [ "one_time", "recurring" ]
          },
          "unit_amount_minor_units": { "type": "integer" },
          "billing_scheme": {
            "type": "string",
            "enum": [ "per_unit", "tiered" ]
          },
          "tiers_mode": {
            "type": "string",
            "enum": [ "graduated", "volume" ],
            "nullable": true
          },
          "recurring_interval": {
            "type": "string",
            "enum": [ "daily", "weekly", "monthly", "quarterly", "yearly" ],
            "nullable": true
          },
          "recurring_interval_count": { "type": "integer" },
          "tax_behavior": {
            "type": "string",
            "enum": [ "inclusive", "exclusive", "unspecified" ]
          },
          "lookup_key": { "type": "string", "nullable": true },
          "custom_amount_enabled": { "type": "boolean" },
          "custom_amount_min_minor_units": { "type": "integer", "nullable": true },
          "custom_amount_max_minor_units": { "type": "integer", "nullable": true },
          "custom_amount_preset_minor_units": { "type": "integer", "nullable": true },
          "tiers": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TierResponse" }
          },
          "metadata": { "type": "object", "additionalProperties": true, "nullable": true },
          "livemode": { "type": "boolean", "description": "Whether the object exists in live mode or test mode" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "archived_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "TierResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "up_to": { "type": "integer", "nullable": true },
          "unit_amount_minor_units": { "type": "integer" },
          "flat_amount_minor_units": { "type": "integer" }
        }
      },
      "CreatePriceRequest": {
        "type": "object",
        "required": [ "product_id", "currency", "price_type", "unit_amount_minor_units" ],
        "properties": {
          "product_id": { "type": "string", "format": "uuid" },
          "currency": { "type": "string" },
          "price_type": {
            "type": "string",
            "enum": [ "one_time", "recurring" ]
          },
          "unit_amount_minor_units": { "type": "integer", "minimum": 0 },
          "billing_scheme": {
            "type": "string",
            "enum": [ "per_unit", "tiered" ]
          },
          "tiers_mode": {
            "type": "string",
            "enum": [ "graduated", "volume" ]
          },
          "tiers": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TierRequest" }
          },
          "recurring_interval": {
            "type": "string",
            "enum": [ "daily", "weekly", "monthly", "quarterly", "yearly" ]
          },
          "recurring_interval_count": { "type": "integer" },
          "tax_behavior": {
            "type": "string",
            "enum": [ "inclusive", "exclusive", "unspecified" ]
          },
          "lookup_key": { "type": "string", "maxLength": 200 },
          "custom_amount_enabled": { "type": "boolean" },
          "custom_amount_min_minor_units": { "type": "integer" },
          "custom_amount_max_minor_units": { "type": "integer" },
          "custom_amount_preset_minor_units": { "type": "integer" },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "TierRequest": {
        "type": "object",
        "required": [ "unit_amount_minor_units" ],
        "properties": {
          "up_to": { "type": "integer", "nullable": true },
          "unit_amount_minor_units": { "type": "integer", "minimum": 0 },
          "flat_amount_minor_units": { "type": "integer", "default": 0 }
        }
      },
      "UpdatePriceRequest": {
        "type": "object",
        "properties": {
          "active": { "type": "boolean" },
          "lookup_key": { "type": "string" },
          "metadata": { "type": "object", "additionalProperties": true }
        }
      },
      "PaginatedPriceResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/PriceResponse" }
          },
          "pagination": { "$ref": "#/components/schemas/PaginationMeta" }
        }
      },
      "DeletedResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "object": { "type": "string" },
          "deleted": { "type": "boolean" }
        }
      }
    }
  }
}
