{
 "openapi": "3.0.3",
 "info": {
  "title": "Bachs API",
  "version": "1.0.0",
  "description": "The Bachs API lets you accept payments, manage subscriptions, and move money across African markets.\n\n- **Authentication:** pass your secret key as `Authorization: Bearer sk_...`. See [Authentication](/authentication) for keys, scopes, and sandbox vs production.\n- **Errors:** every error returns a flat `{ \"detail\", \"error_code\", \"doc_url\" }`. See [Errors](/errors).\n- **Pagination:** list endpoints return `{ items, pagination }`. See [Pagination](/guides/pagination).\n- **Idempotency:** retry `POST` safely with the `Idempotency-Key` header. See [Idempotency](/guides/idempotency).\n- **Base URLs and rate limits:** see the [Introduction](/api-reference/overview).",
  "contact": {
   "name": "Bachs Support",
   "url": "https://bachs.io"
  }
 },
 "servers": [
  {
   "url": "https://api.bachs.io",
   "description": "Production"
  },
  {
   "url": "https://sandbox-api.bachs.io",
   "description": "Sandbox"
  }
 ],
 "security": [
  {
   "ApiKeyAuth": []
  }
 ],
 "tags": [
  {
   "name": "Payments",
   "description": "Accept payments from customers"
  },
  {
   "name": "Refunds",
   "description": "Create and manage customer refunds"
  },
  {
   "name": "Disputes",
   "description": "Respond to chargebacks and manage dispute evidence"
  },
  {
   "name": "Balances",
   "description": "View balances and account information"
  },
  {
   "name": "Conversions",
   "description": "Quote, execute, and query currency conversions"
  },
  {
   "name": "Payouts",
   "description": "Withdraw funds to external accounts"
  },
  {
   "name": "Webhooks",
   "description": "Receive real-time payment notifications"
  },
  {
   "name": "Authentication",
   "description": "API key management and authentication"
  },
  {
   "name": "Customers",
   "description": "Create and manage customers"
  },
  {
   "name": "Products",
   "description": "Define and manage your billing catalog"
  },
  {
   "name": "Product Groups",
   "description": "Bundle products for multi-plan checkout"
  },
  {
   "name": "Media",
   "description": "Upload files and get an upload_id to attach to products"
  },
  {
   "name": "Checkouts",
   "description": "Create and manage API-driven checkouts without products"
  },
  {
   "name": "Subscriptions",
   "description": "Recurring billing. Subscriptions are created through checkout; manage them here."
  },
  {
   "name": "Customer sessions",
   "description": "Open a hosted portal session so a customer can manage their own subscriptions, invoices and cards."
  },
  {
   "name": "Accounts",
   "description": "Create the accounts your platform onboards, request their capabilities, walk them through their requirements, and read what they still owe."
  },
  {
   "name": "Transfers",
   "description": "Move funds between your platform and the accounts you own."
  },
  {
   "name": "Platform Fees",
   "description": "Read the platform's cut of an account's sale."
  }
 ],
 "paths": {
  "/v1/payment-methods": {
   "get": {
    "tags": [
     "Payments"
    ],
    "summary": "List payment methods",
    "description": "Get all available payment methods and their supported currencies. Use this to determine which payment options to show customers.",
    "operationId": "listPaymentMethods",
    "security": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentMethodsResponse"
        },
        "example": {
         "payment_methods": [
          {
           "id": "BANK_TRANSFER",
           "display_name": "Bank Transfer",
           "icon": "bank",
           "description": "Pay via bank transfer",
           "type": "fiat",
           "enabled_by_default": true,
           "currencies": [
            "NGN",
            "USD"
           ]
          },
          {
           "id": "CRYPTO",
           "display_name": "Cryptocurrency",
           "icon": "crypto",
           "description": "Pay with supported crypto assets",
           "type": "crypto",
           "enabled_by_default": true,
           "currencies": [
            "USDT_TRC20",
            "USDT_BEP20"
           ]
          }
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payments/list-payment-methods"
    }
   }
  },
  "/v1/currencies/supported": {
   "get": {
    "tags": [
     "Payments"
    ],
    "summary": "List supported currencies",
    "description": "Get all supported fiat and cryptocurrency codes. Use this to validate currency selections and display currency options to users.",
    "operationId": "listSupportedCurrencies",
    "security": [],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SupportedCurrenciesResponse"
        },
        "example": {
         "fiat": [
          "USD",
          "NGN",
          "GHS",
          "KES",
          "ZAR"
         ],
         "crypto": [
          "USDT_TRC20",
          "USDT_ERC20",
          "BTC"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payments/list-supported-currencies"
    }
   }
  },
  "/v1/payment-methods/rails": {
   "get": {
    "tags": [
     "Payments"
    ],
    "summary": "List payment rails",
    "description": "Get available payment rails for a specific payment method and currency combination. Use this to determine which payment rails are available before creating a quote. The 'id' field from the response should be used as the 'payment_rail' parameter when creating quotes.",
    "operationId": "listPaymentRails",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "payment_method",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string",
       "enum": [
        "CARD",
        "CRYPTO",
        "BANK_TRANSFER",
        "MOBILE_MONEY"
       ]
      },
      "description": "Payment method to get rails for"
     },
     {
      "name": "currency",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Currency code (e.g., 'NGN', 'USD', 'GHS', 'USDT_TRC20')"
     },
     {
      "name": "country_code",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Optional ISO country code (e.g., 'NG', 'GH') to filter rails by country"
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Payment rails retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentRailsResponse"
        },
        "example": {
         "payment_method": "BANK_TRANSFER",
         "currency": "NGN",
         "country_code": "NG",
         "rails": [
          {
           "id": "bank_transfer_ng",
           "name": "Bank Transfer Nigeria",
           "active": true
          }
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payments/list-payment-rails"
    }
   }
  },
  "/v1/currencies/payout-supported": {
   "get": {
    "tags": [
     "Payments"
    ],
    "summary": "List payout supported currencies",
    "description": "Get all currencies that support payouts/withdrawals, organized by fiat and cryptocurrency types.",
    "operationId": "listPayoutSupportedCurrencies",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Payout supported currencies retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutSupportedCurrenciesResponse"
        },
        "example": {
         "fiat": [
          "NGN",
          "USD",
          "GHS"
         ],
         "crypto": [
          "USDT_TRC20",
          "USDT_ERC20"
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payments/list-payout-supported-currencies"
    }
   }
  },
  "/v1/checkout-sessions": {
   "post": {
    "tags": [
     "Checkout Sessions"
    ],
    "summary": "Create a checkout session",
    "description": "Create a product-based checkout session",
    "operationId": "createCheckoutSession",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateCheckoutSessionRequest"
       },
       "example": {
        "customer": {
         "email": "customer@example.com",
         "name": "John Doe"
        },
        "product_cart": [
         {
          "product_id": "prod_abc123"
         }
        ],
        "payment_method_types": [
         "USD_CARD",
         "NGN_BANK_TRANSFER"
        ]
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Success - Checkout session created successfully",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CreateCheckoutSessionResponse"
        },
        "example": {
         "checkout_id": "chk_1M2N3o4P5q6R7s8T",
         "checkout_url": "https://checkout.bachs.io/c/Tb5rHn8YkQ2vXpL",
         "status": "open",
         "expires_at": "2026-01-24T15:30:00.000Z",
         "created_at": "2026-01-24T14:30:00.000Z",
         "reference": "order_9876"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payments/create-checkout-session"
    }
   }
  },
  "/v1/payments/charges/{charge_id}": {
   "get": {
    "tags": [
     "Payments"
    ],
    "summary": "Get Charge Status",
    "description": "Check the status of a payment charge. Use this to poll payment status or verify completion after webhook notifications.",
    "operationId": "getChargeStatus",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "charge_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Charge ID from checkout or payment"
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Charge status retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ChargeStatusResponse"
        },
        "example": {
         "charge_id": "ch_1a2b3c4d5e6f",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "customer_id": "cust_xyz789",
         "amount": "75000.00",
         "currency": "NGN",
         "settlement_currency": "NGN",
         "settlement_amount": "74250.00",
         "status": "succeeded",
         "metadata": {
          "order_id": "ORD-12345",
          "product_sku": "PREMIUM-ANNUAL"
         },
         "status_history": [
          {
           "status": "created",
           "occurred_at": "2026-01-24T14:30:00.000Z",
           "reason": null
          },
          {
           "status": "processing",
           "occurred_at": "2026-01-24T14:30:30.000Z",
           "reason": null
          },
          {
           "status": "succeeded",
           "occurred_at": "2026-01-24T14:35:00.000Z",
           "reason": "Payment received and confirmed"
          }
         ],
         "created_at": "2026-01-24T14:30:00.000Z",
         "updated_at": "2026-01-24T14:35:00.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payments/get-charge-status"
    }
   }
  },
  "/v1/payments": {
   "get": {
    "tags": [
     "Payments"
    ],
    "summary": "List payments",
    "description": "Return a paginated list of payments your account has received, newest first. Filter with query parameters for reconciliation and monitoring. List items carry a summary of each payment; call Retrieve a payment for the full object including fees, products, and status history.",
    "operationId": "listPayments",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      },
      "description": "Page size. Defaults to 50. Maximum is 100."
     },
     {
      "name": "offset",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of records to skip before returning results."
     },
     {
      "name": "status_filter",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "created",
        "processing",
        "succeeded",
        "accepted",
        "failed",
        "expired",
        "cancelled",
        "refunded",
        "partially_refunded",
        "auto_refunded",
        "underpaid",
        "overpaid"
       ]
      },
      "description": "Optional exact status filter for charge records."
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Payments list retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentListResponse"
        },
        "example": {
         "items": [
          {
           "id": "chrg_1a2b3c4d5e",
           "reference": "order_9876",
           "status": "succeeded",
           "is_refundable": true,
           "amount": "10.00",
           "customer_name": "Jane Doe",
           "customer_email": "customer@example.com",
           "amount_paid": "10.00",
           "amount_remaining": "0.00",
           "settlement_amount": "10.00",
           "fee": "0.90",
           "vat": null,
           "currency": "USD",
           "settlement_currency": "USD",
           "meta": null,
           "transaction_date": "2026-04-27T12:00:00Z",
           "completed_at": "2026-04-27T12:00:05Z"
          }
         ],
         "pagination": {
          "next_cursor": null,
          "prev_cursor": null,
          "has_more": false,
          "limit": 50,
          "offset": 0,
          "returned": 1,
          "total": 1
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payments/list-payments"
    }
   }
  },
  "/v1/charges": {
   "post": {
    "tags": [
     "Payments"
    ],
    "summary": "Create a charge",
    "description": "**In beta.** This endpoint might change, including field names and the shape of the response. Pin your integration to what you test.\n\nCharge a customer's saved card off-session, meaning with nobody on a payment page. Use this for money a customer agreed to once and you collect later, such as a usage invoice or a top-up. An off-session charge cannot ask the customer to authenticate, so a card whose issuer demands it is refused.\n\nThe card must have been saved on an earlier checkout. See [Charge a saved card](/guides/payments/charge-a-saved-card).\n\nThis always answers with a payment, never an error, when the card is refused: a refusal is an outcome you read from `status`. The payment is usually `processing`, and the result reaches you as a `collection.succeeded` or `collection.failed` webhook. A card refused while the request is still open comes back already `failed`. A `201` is not payment received.\n\nSend an `Idempotency-Key` header. Without one, a retry after a timeout charges the customer twice.",
    "operationId": "createCharge",
    "x-mint": {
     "metadata": {
      "tag": "Beta"
     }
    },
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateChargeRequest"
       },
       "example": {
        "customer": "cust_1a2b3c4d5e6f",
        "amount": "29.00",
        "currency": "USD",
        "description": "April usage",
        "reference": "INV-2026-04-881"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Success - Charge created and submitted to the card",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentResponse"
        },
        "example": {
         "payment_id": "ch_389305e973a841cc",
         "status": "processing",
         "amount": "30.85",
         "amount_paid": "0.00",
         "amount_remaining": "30.85",
         "currency": "USD",
         "fees": {
          "amount": "1.85",
          "currency": "USD"
         },
         "payment_method": "CARD",
         "checkout_id": null,
         "narration": "April usage",
         "reference": "INV-2026-04-881",
         "billing_reason": "purchase",
         "customer": {
          "name": "Jane Doe",
          "email": "jane@example.com"
         },
         "created_at": "2026-04-27T12:05:00.000Z",
         "updated_at": "2026-04-27T12:05:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    }
   }
  },
  "/v1/payments/{payment_id}": {
   "get": {
    "tags": [
     "Payments"
    ],
    "summary": "Retrieve a payment",
    "description": "Retrieve a single payment by its charge ID, with the full object: amount, status, the customer, fees, the products paid for, refunds, and status history.",
    "operationId": "getPaymentDetail",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "payment_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Charge ID of the payment."
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Payment retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentResponse"
        },
        "example": {
         "reference": "ord_12903",
         "payment_id": "ch_1a2b3c4d5e6f",
         "checkout_id": "chk_1M2N3o4P5q6R7s8T",
         "status": "succeeded",
         "is_refundable": true,
         "amount": "75000.00",
         "amount_paid": "75000.00",
         "amount_remaining": "0.00",
         "currency": "NGN",
         "fee_usd": "0.70",
         "fees": {
          "amount": "1125.00",
          "currency": "NGN"
         },
         "merchant_bears_cost": false,
         "platform_fee": null,
         "fee_paid_by": "merchant",
         "payment_method": "NGN_BANK_TRANSFER",
         "channel": "api",
         "narration": "Order payment ORD-12903",
         "meta": {
          "order_id": "ORD-12903"
         },
         "message": "Successful",
         "customer": {
          "name": "Jane Doe",
          "email": "jane@example.com"
         },
         "created_at": "2026-02-22T12:00:00.000Z",
         "updated_at": "2026-02-22T12:01:30.000Z",
         "completed_at": "2026-02-22T12:01:30.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payments/get-payment"
    }
   }
  },
  "/v1/balances": {
   "get": {
    "tags": [
     "Balances"
    ],
    "summary": "Retrieve balances",
    "description": "Return account balance buckets by currency, including available, locked, and pending amounts, plus a consolidated USD total.",
    "operationId": "getBalances",
    "security": [
     {
      "ApiKeyAuth": [
       "balance:read"
      ]
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Account balances retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AccountBalanceResponse"
        },
        "example": {
         "account_id": "acct_7KpQ2mNv4XbR9dLc",
         "balances": [
          {
           "currency": "NGN",
           "available_balance": "58700.00",
           "pending_balance": "0.00"
          },
          {
           "currency": "USD",
           "available_balance": "95178.20",
           "pending_balance": "0.00"
          }
         ],
         "total_balance_usd": "95221.29",
         "pending_settlements_by_day": []
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/accounts/get-balances"
    }
   }
  },
  "/v1/conversions/quotes": {
   "post": {
    "tags": [
     "Conversions"
    ],
    "summary": "Create Conversion Quote",
    "description": "Create a quote for converting between settlement currencies (USD <-> NGN).",
    "operationId": "createConversionQuote",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ConversionQuoteRequest"
       },
       "example": {
        "from_currency": "USD",
        "to_currency": "NGN",
        "amount": "1000.00"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Success - Conversion quote generated",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ConversionQuoteResponse"
        },
        "example": {
         "quote_id": "cqt_1a2b3c4d5e6f",
         "from_currency": "USD",
         "to_currency": "NGN",
         "from_amount": "1000.00",
         "to_amount": "1500000.00",
         "exchange_rate": "1500.00",
         "expires_at": "2026-01-24T14:31:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/conversions/create-conversion-quote"
    }
   }
  },
  "/v1/conversions": {
   "get": {
    "tags": [
     "Conversions"
    ],
    "summary": "List Conversions",
    "description": "List conversion records for your account with offset pagination.\n\nCommon errors:\n- `400 VALIDATION_ERROR`: One or more query parameters are invalid. Resolution: correct query values and retry.\n- `401 UNAUTHORIZED`: API key is missing, invalid, or revoked. Resolution: use a valid API key in the `Authorization` header.",
    "operationId": "listConversions",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "default": 50,
       "minimum": 1,
       "maximum": 100
      }
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "default": 0,
       "minimum": 0
      }
     },
     {
      "name": "from_currency",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "to_currency",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "status",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "start_date",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "end_date",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Conversions retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ConversionListResponse"
        },
        "example": {
         "total": 2,
         "limit": 20,
         "offset": 0,
         "items": [
          {
           "conversion_id": "cvt_1a2b3c4d5e6f",
           "status": "completed",
           "from_currency": "USD",
           "to_currency": "NGN",
           "from_amount": "1000.00",
           "to_amount": "1500000.00",
           "exchange_rate": "1500.00",
           "created_at": "2026-01-24T14:30:00.000Z"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/conversions/list-conversions"
    }
   },
   "post": {
    "tags": [
     "Conversions"
    ],
    "summary": "Execute Conversion",
    "description": "Execute a conversion between settlement currencies (USD <-> NGN) using a valid quote_id.",
    "operationId": "executeConversion",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ConversionCreateRequest"
       },
       "example": {
        "from_currency": "USD",
        "to_currency": "NGN",
        "amount": "1000.00",
        "quote_id": "cqt_1a2b3c4d5e6f"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Success - Conversion executed",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ConversionResponse"
        },
        "example": {
         "conversion_id": "cvt_1a2b3c4d5e6f",
         "status": "completed",
         "from_currency": "USD",
         "to_currency": "NGN",
         "from_amount": "1000.00",
         "to_amount": "1500000.00",
         "exchange_rate": "1500.00",
         "created_at": "2026-01-24T14:30:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/conversions/execute-conversion"
    }
   }
  },
  "/v1/conversions/{conversion_id}": {
   "get": {
    "tags": [
     "Conversions"
    ],
    "summary": "Get Conversion",
    "description": "Fetch a single conversion by ID.\n\nCommon errors:\n- `401 UNAUTHORIZED`: API key is missing, invalid, or revoked. Resolution: use a valid API key in the `Authorization` header.\n- `404 NOT_FOUND`: No conversion exists for this `conversion_id`. Resolution: verify the conversion ID and retry.",
    "operationId": "getConversion",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "conversion_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Conversion retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ConversionResponse"
        },
        "example": {
         "conversion_id": "cvt_1a2b3c4d5e6f",
         "status": "completed",
         "from_currency": "USD",
         "to_currency": "NGN",
         "from_amount": "1000.00",
         "to_amount": "1500000.00",
         "exchange_rate": "1500.00",
         "created_at": "2026-01-24T14:30:00.000Z",
         "quote_id": "cqt_1a2b3c4d5e6f",
         "metadata": null
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/conversions/get-conversion"
    }
   }
  },
  "/v1/payouts/quotes": {
   "post": {
    "tags": [
     "Payouts"
    ],
    "summary": "Create Payout Quote",
    "description": "Lock an exchange rate for a payout that delivers a different currency from the balance it debits. Returns a `quote_id` to pass to Create Payout in place of `amount`, along with the rate and the amount the destination receives. Same-currency payouts need no quote. The quote carries no fee: the payout fee is charged on top of the amount when the payout is created.",
    "operationId": "createPayoutQuote",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/PayoutQuoteRequest"
       },
       "example": {
        "from_currency": "USD",
        "to_currency": "NGN",
        "amount": "100.00"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Success - Payout quote generated",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutQuoteResponse"
        },
        "example": {
         "quote_id": "pqt_1a2b3c4d5e6f",
         "from_currency": "USD",
         "to_currency": "NGN",
         "from_amount": "100.00",
         "to_amount": "148500.00",
         "exchange_rate": "1500.00",
         "expires_at": "2026-02-22T12:31:00+00:00"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/create-payout-quote"
    }
   }
  },
  "/v1/payouts/destinations": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "summary": "List Payout Destinations",
    "description": "List all configured payout destinations (bank accounts, mobile money, crypto wallets) for your account.",
    "operationId": "listPayoutDestinations",
    "security": [
     {
      "ApiKeyAuth": [
       "payouts:read"
      ]
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Payout destinations list retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutDestinationListResponse"
        },
        "example": {
         "destinations": [
          {
           "id": "pd_7Kq2mNv4XbR9dLc0",
           "name": "My GTBank Savings",
           "type": "bank_account",
           "currency": "NGN",
           "status": "approved",
           "status_reason": null,
           "is_usable": true,
           "is_default": false,
           "account_number": "0123456789",
           "account_name": "JOHN DOE",
           "bank_code": "058",
           "bank_name": "Guaranty Trust Bank",
           "phone_number": null,
           "mobile_provider": null,
           "wallet_address": null,
           "network": null,
           "reviewed_at": "2026-01-24T15:00:00.000Z",
           "created_at": "2026-01-24T14:30:00.000Z",
           "updated_at": "2026-01-24T14:30:00.000Z"
          }
         ],
         "total": 1,
         "limit": 20,
         "offset": 0
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/list-payout-destinations"
    },
    "parameters": [
     {
      "name": "currency",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Filter by destination currency code."
     },
     {
      "name": "status",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "pending_review",
        "approved",
        "rejected"
       ]
      },
      "description": "Filter by admin review status: `pending_review`, `approved`, or `rejected`."
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 20
      },
      "description": "Number of records to return."
     },
     {
      "name": "offset",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of records to skip."
     }
    ]
   },
   "post": {
    "tags": [
     "Payouts"
    ],
    "summary": "Create Payout Destination",
    "description": "Add a new payout destination (bank account, mobile money, or crypto wallet) where you can withdraw funds.",
    "operationId": "createPayoutDestination",
    "security": [
     {
      "ApiKeyAuth": [
       "payouts:write"
      ]
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreatePayoutDestinationRequest"
       },
       "example": {
        "name": "My GTBank Savings",
        "currency": "NGN",
        "label": "Treasury NGN Account",
        "account_number": "0123456789",
        "bank_code": "058"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutDestinationResponse"
        },
        "example": {
         "id": "pd_7Kq2mNv4XbR9dLc0",
         "name": "My GTBank Savings",
         "type": "bank_account",
         "currency": "NGN",
         "status": "pending_review",
         "status_reason": null,
         "is_usable": false,
         "is_default": false,
         "account_number": "0123456789",
         "account_name": "JOHN DOE",
         "bank_code": "058",
         "bank_name": "Guaranty Trust Bank",
         "phone_number": null,
         "mobile_provider": null,
         "wallet_address": null,
         "network": null,
         "reviewed_at": null,
         "created_at": "2026-01-24T14:30:00.000Z",
         "updated_at": "2026-01-24T14:30:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/create-payout-destination"
    }
   }
  },
  "/v1/payouts/destinations/{destination_id}": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "summary": "Get Payout Destination",
    "description": "Retrieve a single payout destination by ID.",
    "operationId": "getPayoutDestination",
    "security": [
     {
      "ApiKeyAuth": [
       "payouts:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "destination_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutDestinationResponse"
        },
        "example": {
         "id": "pd_7Kq2mNv4XbR9dLc0",
         "name": "Treasury NGN Account",
         "type": "bank_account",
         "currency": "NGN",
         "status": "pending_review",
         "status_reason": null,
         "is_usable": false,
         "is_default": false,
         "account_number": "0123456789",
         "account_name": "JOHN DOE",
         "bank_code": "058",
         "bank_name": "Guaranty Trust Bank",
         "phone_number": null,
         "mobile_provider": null,
         "wallet_address": null,
         "network": null,
         "reviewed_at": null,
         "created_at": "2026-01-24T14:30:00.000Z",
         "updated_at": "2026-02-22T14:30:00.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    }
   },
   "patch": {
    "tags": [
     "Payouts"
    ],
    "summary": "Update Payout Destination",
    "description": "Update a destination: rename it, (de)promote it as a payout schedule's default, or restate where money lands.\n\n`name` and `is_default` alone are safe: neither touches review status, since the default can only ever be one of your own approved destinations. Sending any routing detail (currency, type, account, wallet or phone) restates the destination in full, the same shape as `POST`; omitted routing fields fall back to what is already stored. Changing an account number, bank code, wallet, network, or phone number this way sends the destination back for review, because the approval it holds was granted for the details it is being asked to leave behind.\n\nCommon errors:\n- `400 VALIDATION_ERROR`: neither `name` nor `is_default` sent, or an invalid payload for the destination type. Resolution: validate request fields and retry.\n- `401 UNAUTHORIZED`: API key is missing, invalid, or revoked. Resolution: use a valid API key in the `Authorization` header.\n- `404 NOT_FOUND`: `destination_id` was not found. Resolution: verify destination ID and retry.",
    "operationId": "updatePayoutDestination",
    "security": [
     {
      "ApiKeyAuth": [
       "payouts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "destination_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/UpdatePayoutDestinationRequest"
       },
       "example": {
        "name": "Treasury NGN Account"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutDestinationResponse"
        },
        "example": {
         "id": "pd_7Kq2mNv4XbR9dLc0",
         "name": "Treasury NGN Account",
         "type": "bank_account",
         "currency": "NGN",
         "status": "pending_review",
         "status_reason": null,
         "is_usable": false,
         "is_default": false,
         "account_number": "0123456789",
         "account_name": "JOHN DOE",
         "bank_code": "058",
         "bank_name": "Guaranty Trust Bank",
         "phone_number": null,
         "mobile_provider": null,
         "wallet_address": null,
         "network": null,
         "reviewed_at": null,
         "created_at": "2026-01-24T14:30:00.000Z",
         "updated_at": "2026-02-22T14:30:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    }
   },
   "delete": {
    "tags": [
     "Payouts"
    ],
    "summary": "Delete Payout Destination",
    "description": "Delete a payout destination.",
    "operationId": "deletePayoutDestination",
    "security": [
     {
      "ApiKeyAuth": [
       "payouts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "destination_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success - destination deactivated",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DeletePayoutDestinationResponse"
        },
        "example": {
         "id": "pd_7Kq2mNv4XbR9dLc0",
         "deleted": true
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/delete-payout-destination"
    }
   }
  },
  "/v1/accounts/me": {
   "get": {
    "tags": [
     "Accounts"
    ],
    "summary": "Get your own account",
    "description": "Get the account your API key belongs to, including its capability names, checkout payment methods, and balance currencies. The `capabilities` and `requirements` blocks are not populated here; read the account by ID for those. Use this to confirm your own platform holds an active `connect` capability before you create accounts. See [Become a platform](/connect/become-a-platform).",
    "operationId": "getMyOrganization",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "responses": {
     "200": {
      "description": "Your account.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/OrganizationResponse"
        },
        "example": {
         "id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Ada Stores",
         "owner_user_id": "usr_7b3e19d24c0a",
         "parent_organization_id": null,
         "country": "NG",
         "fee_handling": "account_pays_fee",
         "enabled_payment_methods": {
          "USD_CARD": {
           "enabled": true
          },
          "NGN_CARD": {
           "enabled": true
          },
          "NGN_BANK_TRANSFER": {
           "enabled": true
          },
          "MOMO_GHS": {
           "enabled": true
          },
          "CRYPTO": {
           "enabled": true,
           "currencies": {
            "USDT_TRC20": true,
            "USDC_BEP20": true
           }
          }
         },
         "adaptive_pricing": true,
         "balance_currencies": [
          "NGN",
          "USD"
         ],
         "phone_number": null,
         "company_name": null,
         "enabled_capabilities": [
          "payouts",
          "conversions",
          "connect"
         ],
         "capabilities": null,
         "requirements": null,
         "is_active": true,
         "created_at": "2026-08-01T09:12:44.000Z",
         "updated_at": "2026-08-07T11:04:22.518Z",
         "responsibilities": null,
         "configuration": null
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/organizations/get-my-organization"
    }
   }
  },
  "/v1/accounts/{account_id}": {
   "get": {
    "tags": [
     "Accounts"
    ],
    "summary": "Get an account",
    "description": "Read an account: your own, or one you own. A platform account and an account you own are the same object, differing only by whether they have a parent, so one path serves both. `capabilities` and `requirements` always come back; `include=requirements.values` adds what has been submitted.",
    "operationId": "getAccount",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404` so the response never confirms that an unrelated account exists.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     {
      "name": "include",
      "in": "query",
      "required": false,
      "schema": {
       "type": "array",
       "items": {
        "type": "string",
        "enum": [
         "requirements.values"
        ]
       }
      },
      "style": "form",
      "explode": true,
      "description": "Expandable blocks to add. `requirements.values` returns the account's current field values and the per-person rollup, which cost an extra resource load. Comma-separated or repeated; an unknown value returns `400 invalid_include`. Anything not asked for is omitted from the response rather than returned as null.",
      "example": "requirements.values"
     }
    ],
    "responses": {
     "200": {
      "description": "The account.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/OrganizationResponse"
        },
        "example": {
         "id": "acct_3Wq8ZfT1yHnJ5sVe",
         "name": "Ada Stores",
         "owner_user_id": "usr_5e0b74c8a213",
         "parent_organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "country": "NG",
         "fee_handling": "account_pays_fee",
         "enabled_payment_methods": null,
         "adaptive_pricing": true,
         "balance_currencies": [
          "NGN"
         ],
         "phone_number": null,
         "company_name": null,
         "enabled_capabilities": [
          "payouts"
         ],
         "capabilities": {
          "payouts": {
           "status": "active",
           "requested": true,
           "status_details": null
          },
          "transfers": {
           "status": "restricted",
           "requested": true,
           "status_details": [
            {
             "code": "platform_disabled",
             "resolution": "Contact support to re-enable this capability.",
             "message": "This capability was disabled by the platform."
            }
           ]
          }
         },
         "requirements": {
          "currently_due": [
           "business_profile.social_media"
          ],
          "eventually_due": [],
          "past_due": [],
          "pending_verification": [
           "company.documents.registration"
          ],
          "errors": [
           {
            "field": "company.documents.memart",
            "code": "unreadable",
            "reason": "The document image was too blurry to read."
           }
          ]
         },
         "is_active": true,
         "created_at": "2026-08-01T09:12:44.000Z",
         "updated_at": "2026-08-07T11:04:22.518Z",
         "responsibilities": {
          "fees": {
           "collector": "bachs"
          }
         },
         "configuration": {
          "recipient": {}
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   },
   "post": {
    "tags": [
     "Accounts"
    ],
    "summary": "Update an account",
    "description": "The one write path for an account, yours or one you own. Set its profile and contact details, request capabilities, and supply requirement values in a single call. Omitted keys are left alone.\n\nEach newly requested capability applies the configuration it belongs to, lands as `pending`, and surfaces the requirements it needs. Requesting authorizes nothing: a person enables the capability once those requirements are satisfied. Capabilities cannot be withdrawn once requested. See [Capabilities](/connect/capabilities).",
    "operationId": "updateAccount",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404` so the response never confirms that an unrelated account exists.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/UpdateAccountRequest"
       },
       "example": {
        "display_name": "Ada Stores Ltd",
        "configuration": {
         "recipient": {
          "capabilities": {
           "conversions": {
            "requested": true
           }
          }
         }
        },
        "fields": {
         "business_profile": {
          "url": "https://adastores.example"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The account, including any requirements the newly requested capability just surfaced and the effect of any fields supplied.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/OrganizationResponse"
        },
        "example": {
         "id": "acct_3Wq8ZfT1yHnJ5sVe",
         "name": "Ada Stores",
         "owner_user_id": "usr_5e0b74c8a213",
         "parent_organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "country": "NG",
         "fee_handling": "account_pays_fee",
         "enabled_payment_methods": null,
         "adaptive_pricing": true,
         "balance_currencies": [
          "NGN"
         ],
         "phone_number": null,
         "company_name": null,
         "enabled_capabilities": [
          "payouts"
         ],
         "capabilities": {
          "payouts": {
           "status": "active",
           "requested": true,
           "status_details": null
          },
          "transfers": {
           "status": "restricted",
           "requested": true,
           "status_details": [
            {
             "code": "platform_disabled",
             "resolution": "Contact support to re-enable this capability.",
             "message": "This capability was disabled by the platform."
            }
           ]
          },
          "conversions": {
           "status": "pending",
           "requested": true,
           "status_details": null
          }
         },
         "requirements": {
          "currently_due": [
           "business_profile.social_media"
          ],
          "eventually_due": [],
          "past_due": [],
          "pending_verification": [
           "company.documents.registration"
          ],
          "errors": [
           {
            "field": "company.documents.memart",
            "code": "unreadable",
            "reason": "The document image was too blurry to read."
           }
          ]
         },
         "is_active": true,
         "created_at": "2026-08-01T09:12:44.000Z",
         "updated_at": "2026-08-07T11:04:22.518Z",
         "responsibilities": {
          "fees": {
           "collector": "bachs"
          }
         },
         "configuration": {
          "recipient": {}
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/accounts": {
   "get": {
    "tags": [
     "Accounts"
    ],
    "summary": "List accounts",
    "description": "Returns the accounts linked to your account. Items never carry the `capabilities` or `requirements` blocks; read a single account with [Get account](/api-reference/connected-accounts/get-connected-account) for those. Requires the `connect` capability to be active on your account.",
    "operationId": "listConnectedAccounts",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:read"
      ]
     }
    ],
    "responses": {
     "200": {
      "description": "A page of accounts. Each entry in `items` is an [Account](/api-reference/connected-accounts/get-connected-account).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ConnectedAccountListResponse"
        },
        "example": {
         "items": [
          {
           "id": "acct_3Wq8ZfT1yHnJ5sVe",
           "name": "Ada Stores",
           "owner_user_id": "usr_7b3e19d24c0a",
           "parent_organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "country": "NG",
           "fee_handling": "account_pays_fee",
           "enabled_payment_methods": null,
           "adaptive_pricing": true,
           "balance_currencies": [
            "NGN"
           ],
           "phone_number": null,
           "company_name": null,
           "enabled_capabilities": [
            "transfers"
           ],
           "capabilities": null,
           "requirements": null,
           "is_active": true,
           "created_at": "2026-08-01T09:12:44.000Z",
           "updated_at": "2026-08-07T11:04:22.518Z",
           "responsibilities": null,
           "configuration": null
          }
         ],
         "total": 42,
         "limit": 20,
         "offset": 0
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/organizations/list-connected-accounts"
    },
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 20
      },
      "description": "Number of accounts to return per page."
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of accounts to skip before the page starts."
     }
    ]
   },
   "post": {
    "tags": [
     "Accounts"
    ],
    "summary": "Create an account",
    "description": "Create an account under your platform. The account starts with nothing enabled: the capabilities you request here decide which requirements it is given, and a person enables each capability once those requirements are satisfied. Requires an active `connect` capability on your own platform, and an account cannot create accounts of its own. See [Create an account](/connect/accounts).",
    "operationId": "createConnectedAccount",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "X-Account-Id",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Account ID when acting on behalf of a sub-account."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateConnectedAccountRequest"
       },
       "example": {
        "contact_email": "ada@adastores.example",
        "display_name": "Ada Stores",
        "first_name": "Ada",
        "last_name": "Okafor",
        "country": "NG",
        "entity_type": "company",
        "configuration": {
         "recipient": {
          "capabilities": {
           "payouts": {
            "requested": true
           },
           "transfers": {
            "requested": true
           }
          }
         }
        },
        "responsibilities": {
         "fees": {
          "collector": "bachs"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Account created, with the requirements the requested capabilities just surfaced.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/OrganizationResponse"
        },
        "example": {
         "id": "acct_3Wq8ZfT1yHnJ5sVe",
         "name": "Ada Stores",
         "owner_user_id": "usr_5e0b74c8a213",
         "parent_organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "country": "NG",
         "fee_handling": "account_pays_fee",
         "enabled_payment_methods": null,
         "adaptive_pricing": true,
         "balance_currencies": [
          "NGN"
         ],
         "phone_number": null,
         "company_name": null,
         "enabled_capabilities": [],
         "capabilities": {
          "payouts": {
           "status": "pending",
           "requested": true,
           "status_details": null
          },
          "transfers": {
           "status": "pending",
           "requested": true,
           "status_details": null
          }
         },
         "requirements": {
          "currently_due": [
           "persons",
           "company.registered_name",
           "company.registration_number",
           "payout_destination"
          ],
          "eventually_due": [],
          "past_due": [],
          "pending_verification": [],
          "errors": []
         },
         "is_active": true,
         "created_at": "2026-08-07T11:04:22.518Z",
         "updated_at": "2026-08-07T11:04:22.518Z",
         "responsibilities": {
          "fees": {
           "collector": "bachs"
          }
         },
         "configuration": {
          "recipient": {}
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/webhooks/replay": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Replay a webhook event",
    "description": "Replay a previously generated webhook event by creating a new outbound delivery attempt. Use this when your endpoint missed or rejected an earlier delivery and you need Bachs to send that event again.\n\nCommon errors:\n- `400 BAD_REQUEST`: No supported lookup field was provided. Resolution: provide at least one of `event_id`, `charge_id`, or `reference`.\n- `401 UNAUTHORIZED`: Authorization is missing, invalid, or revoked. Resolution: send a valid bearer credential.\n- `404 NOT_FOUND`: No matching webhook event could be resolved for your lookup values. Resolution: verify IDs/references and retry.",
    "operationId": "replayWebhookEvent",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "event_id": {
          "type": "string",
          "description": "Webhook event ID to replay directly."
         },
         "charge_id": {
          "type": "string",
          "description": "Charge ID used to resolve the latest webhook event for that charge."
         },
         "reference": {
          "type": "string",
          "description": "Checkout reference used to resolve charge and replay latest webhook event."
         }
        },
        "description": "Provide at least one identifier. If `event_id` is provided, that exact event is replayed. Otherwise, the replay target is resolved by `charge_id` or `reference`.",
        "anyOf": [
         {
          "required": [
           "event_id"
          ]
         },
         {
          "required": [
           "charge_id"
          ]
         },
         {
          "required": [
           "reference"
          ]
         }
        ]
       },
       "example": {
        "event_id": "evt_3ab4e0d5d27445cf8a52ab3d8cb8f0b1"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Success - replay request accepted and a new delivery attempt was created.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "event_id",
          "attempt_id",
          "attempt_no",
          "event_type"
         ],
         "properties": {
          "event_id": {
           "type": "string",
           "description": "The event that was replayed. It keeps its original ID, so a replay is a fresh delivery of the same event rather than a new event.",
           "example": "evt_3ab4e0d5d27445cf8a52ab3d8cb8f0b1"
          },
          "attempt_id": {
           "type": "string",
           "description": "The delivery attempt this replay created. Look it up to see whether the delivery succeeded.",
           "example": "wha_6f1e40f6bdf84c1980e1e1f6407f3f8a"
          },
          "attempt_no": {
           "type": "integer",
           "description": "Which attempt this is for the event, counting every earlier automatic retry.",
           "example": 3
          },
          "event_type": {
           "type": "string",
           "description": "The type of the event that was replayed, the same value your endpoint receives in the payload.",
           "example": "collection.failed"
          }
         }
        },
        "example": {
         "event_id": "evt_3ab4e0d5d27445cf8a52ab3d8cb8f0b1",
         "attempt_id": "wha_6f1e40f6bdf84c1980e1e1f6407f3f8a",
         "attempt_no": 3,
         "event_type": "collection.failed"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/webhooks/replay-webhook-event"
    }
   }
  },
  "/v1/accounts/checkout/settings": {
   "get": {
    "tags": [
     "Accounts"
    ],
    "summary": "Get checkout settings",
    "description": "Retrieve checkout configuration for your account context, including enabled payment methods, per-method currency toggles, and fee preference.",
    "operationId": "getCheckoutSettings",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "X-Account-Id",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Account ID when acting on behalf of a sub-account."
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Checkout settings retrieved",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "organization_id": {
           "type": "string",
           "description": "The account these settings apply to, which is the account your API key belongs to, or the account you named in `X-Account-Id`.",
           "example": "acct_7KpQ2mNv4XbR9dLc"
          },
          "enabled_payment_methods": {
           "type": "object",
           "additionalProperties": {
            "type": "object",
            "properties": {
             "enabled": {
              "type": "boolean"
             },
             "currencies": {
              "type": "object",
              "additionalProperties": {
               "type": "boolean"
              }
             }
            }
           },
           "description": "The methods a customer can pay with at checkout, keyed by exact corridor (`USD_CARD`, `NGN_CARD`, `NGN_BANK_TRANSFER`, `MOMO_GHS`..`MOMO_ZMW`, `CRYPTO`) -- see [payment method support](/guides/payments/payment-method-support). Each entry carries an `enabled` flag; `CRYPTO` alone additionally carries a `currencies` map (per-asset toggles), since every other corridor already names its one currency in the key itself."
          },
          "fee_preference": {
           "type": "string",
           "enum": [
            "customer_pays",
            "org_pays"
           ],
           "description": "Who pays the processing fee on a checkout, unless the individual checkout overrides it. `customer_pays`: the fee is added on top of the amount the customer pays, so you settle the full amount. `org_pays`: you absorb the fee and it is netted out of what settles into your balance.",
           "example": "customer_pays"
          },
          "available_currencies": {
           "type": "object",
           "additionalProperties": {
            "type": "array",
            "items": {
             "type": "string"
            }
           },
           "description": "Every currency each corridor is configured to accept on the platform, keyed by the same exact corridors as `enabled_payment_methods`, so you know which currencies you can switch on before you send an update."
          }
         }
        },
        "example": {
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "enabled_payment_methods": {
          "USD_CARD": {
           "enabled": true
          },
          "NGN_CARD": {
           "enabled": false
          },
          "NGN_BANK_TRANSFER": {
           "enabled": true
          },
          "MOMO_GHS": {
           "enabled": true
          },
          "MOMO_XAF": {
           "enabled": true
          },
          "MOMO_XOF": {
           "enabled": true
          },
          "CRYPTO": {
           "enabled": true,
           "currencies": {
            "BNB_BEP20": false,
            "ETH_ETH": false,
            "SOL_SOL": false,
            "USDC_BEP20": false,
            "USDT_BEP20": true,
            "USDT_ERC20": false,
            "USDT_SOL": false,
            "USDT_TRC20": true
           }
          }
         },
         "fee_preference": "customer_pays",
         "available_currencies": {
          "USD_CARD": [
           "USD"
          ],
          "NGN_CARD": [
           "NGN"
          ],
          "NGN_BANK_TRANSFER": [
           "NGN"
          ],
          "MOMO_GHS": [
           "GHS"
          ],
          "CRYPTO": [
           "BNB_BEP20",
           "ETH_ETH",
           "SOL_SOL",
           "USDC_BEP20",
           "USDT_BEP20",
           "USDT_ERC20",
           "USDT_SOL",
           "USDT_TRC20"
          ]
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/organizations/get-checkout-settings"
    }
   },
   "put": {
    "tags": [
     "Accounts"
    ],
    "summary": "Update checkout settings",
    "description": "Update checkout configuration for your account context, including enabled payment methods and fee preference.",
    "operationId": "updateCheckoutSettings",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "X-Account-Id",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Account ID when acting on behalf of a sub-account."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "enabled_payment_methods": {
          "type": "object",
          "additionalProperties": {
           "type": "object",
           "properties": {
            "enabled": {
             "type": "boolean"
            },
            "currencies": {
             "type": "object",
             "additionalProperties": {
              "type": "boolean"
             }
            }
           }
          },
          "description": "The corridors to offer at checkout, keyed by exact corridor (`USD_CARD`, `NGN_CARD`, `NGN_BANK_TRANSFER`, `MOMO_GHS`..`MOMO_ZMW`, `CRYPTO`) -- see [payment method support](/guides/payments/payment-method-support). Each entry you send must carry an `enabled` boolean; `CRYPTO` additionally accepts a `currencies` map of per-asset booleans. This replaces the stored configuration wholesale: a corridor you omit resets to its platform default rather than keeping its current state."
         },
         "fee_preference": {
          "type": "string",
          "enum": [
           "customer_pays",
           "org_pays"
          ],
          "description": "Who pays the processing fee on a checkout from now on. `customer_pays`: the fee is added on top of the amount the customer pays, so you settle the full amount. `org_pays`: you absorb the fee and it is netted out of what settles into your balance. Omit the field to leave the current preference untouched.",
          "example": "org_pays"
         }
        },
        "description": "Provide one or both fields: `enabled_payment_methods` and `fee_preference`.",
        "anyOf": [
         {
          "required": [
           "enabled_payment_methods"
          ]
         },
         {
          "required": [
           "fee_preference"
          ]
         }
        ]
       },
       "example": {
        "enabled_payment_methods": {
         "USD_CARD": {
          "enabled": true
         },
         "NGN_BANK_TRANSFER": {
          "enabled": true
         },
         "MOMO_GHS": {
          "enabled": true
         },
         "MOMO_XAF": {
          "enabled": true
         },
         "MOMO_XOF": {
          "enabled": true
         },
         "CRYPTO": {
          "enabled": false,
          "currencies": {
           "BNB_BEP20": false,
           "ETH_ETH": false,
           "SOL_SOL": false,
           "USDC_BEP20": false,
           "USDT_BEP20": false,
           "USDT_ERC20": false,
           "USDT_SOL": false,
           "USDT_TRC20": false
          }
         }
        },
        "fee_preference": "org_pays"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Success - Checkout settings updated",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "organization_id": {
           "type": "string",
           "description": "The account whose settings were updated, which is the account your API key belongs to, or the account you named in `X-Account-Id`.",
           "example": "acct_7KpQ2mNv4XbR9dLc"
          },
          "enabled_payment_methods": {
           "type": "object",
           "additionalProperties": {
            "type": "object"
           },
           "description": "The stored configuration after the update, keyed by exact corridor. The update replaces the whole map, so this returns the corridors you sent and nothing else. Read it back to confirm which corridors are now live at checkout."
          },
          "fee_preference": {
           "type": "string",
           "enum": [
            "customer_pays",
            "org_pays"
           ],
           "description": "Who now pays the processing fee on a checkout. `customer_pays`: the fee is added on top of the amount the customer pays, so you settle the full amount. `org_pays`: you absorb the fee and it is netted out of what settles into your balance.",
           "example": "org_pays"
          },
          "message": {
           "type": "string",
           "description": "A confirmation string for the update. Do not branch on it, since the returned `enabled_payment_methods` and `fee_preference` carry the state you should check.",
           "example": "Checkout settings updated successfully"
          }
         }
        },
        "example": {
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "enabled_payment_methods": {
          "USD_CARD": {
           "enabled": true
          },
          "NGN_BANK_TRANSFER": {
           "enabled": true
          },
          "MOMO_GHS": {
           "enabled": true
          },
          "MOMO_XAF": {
           "enabled": true
          },
          "MOMO_XOF": {
           "enabled": true
          },
          "CRYPTO": {
           "enabled": false,
           "currencies": {
            "BNB_BEP20": false,
            "ETH_ETH": false,
            "SOL_SOL": false,
            "USDC_BEP20": false,
            "USDT_BEP20": false,
            "USDT_ERC20": false,
            "USDT_SOL": false,
            "USDT_TRC20": false
           }
          }
         },
         "fee_preference": "org_pays",
         "message": "Checkout settings updated successfully"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/organizations/update-checkout-settings"
    }
   }
  },
  "/v1/balance_settings": {
   "get": {
    "tags": [
     "Balances"
    ],
    "summary": "Get payout schedule",
    "description": "Read the payout schedule for your account, or for a connected account named by `X-Account-Id`. Its own resource rather than a block on the account object, so a platform can read timing without pulling the whole account.",
    "operationId": "getPayoutSchedule",
    "security": [
     {
      "ApiKeyAuth": [
       "balance:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "X-Account-Id",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Read the schedule of a connected account you own instead of your own. Same resolution every other API-key route uses: the account must be yours or one you own, or the request 404s."
     }
    ],
    "responses": {
     "200": {
      "description": "The account's payout schedule, keyed by currency. A currency with no schedule is absent rather than present and empty.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutSettingsResponse"
        },
        "example": {
         "schedule_by_currency": {
          "NGN": {
           "currency": "NGN",
           "payout_currency": "NGN",
           "interval": "weekly",
           "weekly_payout_days": [
            "monday",
            "thursday"
           ],
           "monthly_payout_days": null,
           "anchor_hour_utc": 9,
           "minimum_amount": "5000.00",
           "next_run_at": "2026-08-13T09:00:00.000Z",
           "last_run_at": null,
           "last_withdrawal_id": null,
           "disabled_reason": null
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/get-payout-schedule"
    }
   },
   "post": {
    "tags": [
     "Balances"
    ],
    "summary": "Update payout schedule",
    "description": "Set the payout schedule for your account, or for a connected account named by `X-Account-Id`. A currency you leave out of `schedule_by_currency` keeps the schedule it has; a currency you name is replaced in full. See [Payout Schedules](/guides/payouts/payout-schedules).",
    "operationId": "updatePayoutSchedule",
    "security": [
     {
      "ApiKeyAuth": [
       "balance:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "X-Account-Id",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Set the schedule of a connected account you own instead of your own. Same resolution every other API-key route uses: the account must be yours or one you own, or the request 404s."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/PayoutSettingsRequest"
       },
       "example": {
        "schedule_by_currency": {
         "NGN": {
          "interval": "weekly",
          "weekly_payout_days": [
           "monday",
           "thursday"
          ],
          "anchor_hour_utc": 9,
          "minimum_amount": "5000.00"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The account's payout schedule after the write.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutSettingsResponse"
        },
        "example": {
         "schedule_by_currency": {
          "NGN": {
           "currency": "NGN",
           "payout_currency": "NGN",
           "interval": "weekly",
           "weekly_payout_days": [
            "monday",
            "thursday"
           ],
           "monthly_payout_days": null,
           "anchor_hour_utc": 9,
           "minimum_amount": "5000.00",
           "next_run_at": "2026-08-13T09:00:00.000Z",
           "last_run_at": null,
           "last_withdrawal_id": null,
           "disabled_reason": null
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/update-payout-schedule"
    }
   }
  },
  "/v1/payouts": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "summary": "List Payouts",
    "description": "List payout withdrawals for your account.",
    "operationId": "listPayouts",
    "security": [
     {
      "ApiKeyAuth": [
       "payouts:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      },
      "description": "Number of records to return."
     },
     {
      "name": "offset",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of records to skip."
     },
     {
      "name": "status_filter",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "requested",
        "pending",
        "processing",
        "approved",
        "rejected",
        "completed",
        "failed"
       ]
      },
      "description": "Optional exact withdrawal status filter."
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Payout list retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutListResponse"
        },
        "example": {
         "total": 1,
         "items": [
          {
           "id": "pay_4Xr9dLc0mNv7Kq2B",
           "status": "processing",
           "amount": "5000.00",
           "currency": "NGN",
           "source_currency": "NGN",
           "fee": "100.00",
           "total_debited": "5100.00",
           "destination": "pd_7Kq2mNv4XbR9dLc0",
           "reference": "WD-20260222-001",
           "failure_reason": null,
           "created_at": "2026-02-22T12:00:00.000Z",
           "completed_at": null
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/list-payouts"
    }
   },
   "post": {
    "tags": [
     "Payouts"
    ],
    "summary": "Create Payout",
    "description": "Send money to a payout destination you have registered. `amount` is what the destination receives, and the fee is charged on top, so the balance must cover `total_debited`. Paying out in a different currency from the balance you are debiting omits `amount` and passes `quote_id` instead.",
    "operationId": "createPayout",
    "security": [
     {
      "ApiKeyAuth": [
       "payouts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "Idempotency-Key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Recommended. If the same key is retried with an identical request body, the cached response is returned rather than sending a second payout. Retrying the same key with a different body returns `409 IDEMPOTENCY_CONFLICT`."
     },
     {
      "name": "X-Account-Id",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Pay out on behalf of an account you own rather than your own account. The destination, balance, and payout are all scoped to that party."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreatePayoutRequest"
       },
       "example": {
        "destination": "pd_7Kq2mNv4XbR9dLc0",
        "amount": "5000.00",
        "reference": "payout-2026-08-07-001"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Success - Payout created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CreatePayoutResponse"
        },
        "example": {
         "id": "pay_4Xr9dLc0mNv7Kq2B",
         "status": "pending",
         "amount": "5000.00",
         "currency": "NGN",
         "source_currency": "NGN",
         "fee": "100.00",
         "total_debited": "5100.00",
         "destination": "pd_7Kq2mNv4XbR9dLc0",
         "reference": "payout-2026-08-07-001",
         "failure_reason": null,
         "created_at": "2026-08-07T14:30:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/create-payout"
    }
   }
  },
  "/v1/payouts/{withdrawal_id}": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "summary": "Get Payout",
    "description": "Get a payout withdrawal by ID.",
    "operationId": "getPayout",
    "security": [
     {
      "ApiKeyAuth": [
       "payouts:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "withdrawal_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Withdrawal ID."
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Payout retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutResponse"
        },
        "example": {
         "id": "pay_4Xr9dLc0mNv7Kq2B",
         "status": "processing",
         "amount": "5000.00",
         "currency": "NGN",
         "source_currency": "NGN",
         "fee": "100.00",
         "total_debited": "5100.00",
         "destination": "pd_7Kq2mNv4XbR9dLc0",
         "reference": "WD-20260222-001",
         "failure_reason": null,
         "created_at": "2026-02-22T12:00:00.000Z",
         "completed_at": null
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/payouts/get-payout"
    }
   }
  },
  "/v1/refunds": {
   "post": {
    "tags": [
     "Refunds"
    ],
    "summary": "Create a refund",
    "description": "Create a refund for a completed payment. Only one refund can be created per charge.",
    "operationId": "createRefund",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateRefundRequest"
       },
       "example": {
        "charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
        "reference": "RF-20260713-0042",
        "amount": "29.00",
        "fee_bearer": "org",
        "reason": "Customer requested cancellation",
        "idempotency_key": "RF-20260713-0042"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Success - Refund created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RefundResponse"
        },
        "example": {
         "refund_id": "b7f2c41a-9d38-4e6b-8c15-2a7d0e934f61",
         "charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
         "reference": "RF-20260713-0042",
         "status": "processing",
         "requested_amount": "29.00",
         "refunded_amount": null,
         "refund_fee_amount": "0.00",
         "fee_bearer": "org",
         "reason": "Customer requested cancellation",
         "created_at": "2026-07-13T14:20:00.000Z",
         "updated_at": "2026-07-13T14:20:00.000Z",
         "completed_at": null
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/refunds/create-refund"
    }
   },
   "get": {
    "tags": [
     "Refunds"
    ],
    "summary": "List refunds",
    "description": "Retrieve a paginated list of refunds for your account, ordered from most recent to oldest.",
    "operationId": "listRefunds",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      },
      "description": "Number of refunds to return. Min 1, max 100. Default 50."
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of refunds to skip before returning results. Default 0."
     },
     {
      "name": "status",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "processing",
        "success",
        "failed"
       ]
      },
      "description": "Return only refunds in this state. `processing`: the refund is on its way to the customer. `success`: the customer has been refunded. `failed`: the refund did not complete and the money stayed put."
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Refunds listed",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RefundListResponse"
        },
        "example": {
         "total": 2,
         "items": [
          {
           "refund_id": "b7f2c41a-9d38-4e6b-8c15-2a7d0e934f61",
           "charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
           "reference": "RF-20260713-0042",
           "status": "success",
           "requested_amount": "29.00",
           "refunded_amount": "29.00",
           "refund_fee_amount": "0.00",
           "fee_bearer": "org",
           "reason": "Customer requested cancellation",
           "created_at": "2026-07-13T14:20:00.000Z",
           "updated_at": "2026-07-13T14:26:41.220Z",
           "completed_at": "2026-07-13T14:26:41.220Z"
          },
          {
           "refund_id": "5e91d7c3-84b0-4a26-9df1-6c027b3849ea",
           "charge_id": "ch_71c3f8e0a94b25d6c8f10e4a3b975d2c",
           "reference": "RF-20260711-0007",
           "status": "failed",
           "requested_amount": "75000.00",
           "refunded_amount": null,
           "refund_fee_amount": "0.00",
           "fee_bearer": "org",
           "reason": "Duplicate order",
           "created_at": "2026-07-11T16:02:11.870Z",
           "updated_at": "2026-07-11T16:04:58.310Z",
           "completed_at": "2026-07-11T16:04:58.310Z"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/refunds/list-refunds"
    }
   }
  },
  "/v1/refunds/{refund_id}": {
   "get": {
    "tags": [
     "Refunds"
    ],
    "summary": "Retrieve a refund",
    "description": "Retrieve a single refund by its ID.",
    "operationId": "getRefund",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "refund_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The unique identifier for the refund."
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Refund retrieved",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RefundResponse"
        },
        "example": {
         "refund_id": "b7f2c41a-9d38-4e6b-8c15-2a7d0e934f61",
         "charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
         "reference": "RF-20260713-0042",
         "status": "success",
         "requested_amount": "29.00",
         "refunded_amount": "29.00",
         "refund_fee_amount": "0.00",
         "fee_bearer": "org",
         "reason": "Customer requested cancellation",
         "created_at": "2026-07-13T14:20:00.000Z",
         "updated_at": "2026-07-13T14:26:41.220Z",
         "completed_at": "2026-07-13T14:26:41.220Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/refunds/get-refund"
    }
   }
  },
  "/v1/disputes": {
   "get": {
    "tags": [
     "Disputes"
    ],
    "summary": "List Disputes",
    "description": "Retrieve a paginated list of disputes for your account. Results are returned with the most recently created disputes first.",
    "operationId": "listDisputes",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "description": "Number of disputes to return. Minimum 1 and maximum 100.",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      }
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "description": "Number of disputes to skip before returning results.",
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      }
     },
     {
      "name": "status",
      "in": "query",
      "required": false,
      "description": "Filter disputes by status.",
      "schema": {
       "type": "string",
       "enum": [
        "needs_response",
        "under_review",
        "won",
        "lost",
        "closed"
       ]
      }
     },
     {
      "name": "from_date",
      "in": "query",
      "required": false,
      "description": "Return disputes created at or after this timestamp (ISO 8601).",
      "schema": {
       "type": "string",
       "format": "date-time"
      }
     },
     {
      "name": "to_date",
      "in": "query",
      "required": false,
      "description": "Return disputes created at or before this timestamp (ISO 8601).",
      "schema": {
       "type": "string",
       "format": "date-time"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Disputes retrieved successfully.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DisputeListResponse"
        },
        "example": {
         "total": 1,
         "items": [
          {
           "dispute_id": "dsp_3e7b1c9a2f48",
           "charge_id": "ch_8f3a1c9b4e72",
           "amount": "75.00",
           "currency": "USD",
           "status": "needs_response",
           "is_response_editable": true,
           "reason": "fraudulent",
           "response_deadline_at": "2026-03-23T23:59:59.000Z",
           "created_at": "2026-03-09T08:00:00.000Z",
           "updated_at": "2026-03-09T08:00:00.000Z"
          }
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/disputes/list-disputes"
    }
   }
  },
  "/v1/disputes/{dispute_id}": {
   "get": {
    "tags": [
     "Disputes"
    ],
    "summary": "Get Dispute",
    "description": "Retrieve full details for a single dispute, including the current evidence draft and latest submission metadata.",
    "operationId": "getDispute",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "dispute_id",
      "in": "path",
      "required": true,
      "description": "Unique identifier for the dispute.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Dispute retrieved successfully.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DisputeResponse"
        },
        "example": {
         "dispute_id": "dsp_3e7b1c9a2f48",
         "charge_id": "ch_8f3a1c9b4e72",
         "amount": "75.00",
         "currency": "USD",
         "status": "under_review",
         "is_response_editable": false,
         "reason": "fraudulent",
         "response_deadline_at": "2026-03-23T23:59:59.000Z",
         "evidence": {
          "customer_name": "Amara Osei",
          "customer_email_address": "customer@example.com",
          "product_description": "Annual SaaS subscription, plan ID PLAN-PRO-001",
          "service_date": "2026-03-01",
          "notes": "Customer confirmed delivery via email on March 5.",
          "customer_communication_attachment_id": "upl_9f2c7b3d1e45"
         },
         "latest_submission": {
          "submission_id": "dse_a1b2c3d4e5f6",
          "status": "submitted",
          "trigger_source": "merchant_submit",
          "submitted_at": "2026-03-10T09:15:00.000Z",
          "failed_at": null,
          "attempt_sequence": 1
         },
         "created_at": "2026-03-09T08:00:00.000Z",
         "updated_at": "2026-03-10T09:15:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/disputes/get-dispute"
    }
   }
  },
  "/v1/disputes/uploads": {
   "post": {
    "tags": [
     "Disputes"
    ],
    "summary": "Upload Dispute Document",
    "description": "Upload a supporting document for a dispute and receive a document identifier for evidence submission.",
    "operationId": "uploadDisputeDocument",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "multipart/form-data": {
       "schema": {
        "type": "object",
        "required": [
         "file"
        ],
        "properties": {
         "file": {
          "type": "string",
          "format": "binary",
          "description": "Document file to upload (PDF, JPEG, PNG, or GIF up to 10 MB)."
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Document uploaded successfully.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DisputeDocumentUploadResponse"
        },
        "example": {
         "document_id": "upl_9f2c7b3d1e45",
         "file_name": "email-screenshot.pdf",
         "mime_type": "application/pdf",
         "file_size_bytes": 204800,
         "uploaded_at": "2026-03-09T10:00:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/disputes/upload-dispute-document"
    }
   }
  },
  "/v1/disputes/{dispute_id}/evidence": {
   "patch": {
    "tags": [
     "Disputes"
    ],
    "summary": "Update Dispute Evidence",
    "description": "Save or update dispute evidence fields before final submission. Evidence can be updated iteratively while the dispute remains editable.",
    "operationId": "updateDisputeEvidence",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "dispute_id",
      "in": "path",
      "required": true,
      "description": "Unique identifier for the dispute.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/DisputeEvidenceUpdateRequest"
       },
       "example": {
        "customer_name": "Amara Osei",
        "customer_email_address": "customer@example.com",
        "product_description": "Annual SaaS subscription, plan ID PLAN-PRO-001",
        "service_date": "2026-03-01",
        "notes": "Customer confirmed delivery via email on March 5.",
        "customer_communication_attachment_id": "upl_9f2c7b3d1e45"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Evidence updated successfully.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DisputeEvidenceUpdateResponse"
        },
        "example": {
         "dispute_id": "dsp_3e7b1c9a2f48",
         "status": "needs_response",
         "is_response_editable": true,
         "evidence_updated_at": "2026-03-09T11:30:00.000Z"
        }
       }
      }
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/disputes/update-dispute-evidence"
    }
   }
  },
  "/v1/disputes/{dispute_id}/submit": {
   "post": {
    "tags": [
     "Disputes"
    ],
    "summary": "Submit Dispute",
    "description": "Submit saved dispute evidence for network review. This action is irreversible and locks further evidence edits.",
    "operationId": "submitDispute",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "dispute_id",
      "in": "path",
      "required": true,
      "description": "Unique identifier for the dispute.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Dispute evidence submitted successfully.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DisputeSubmitResponse"
        },
        "example": {
         "dispute_id": "dsp_3e7b1c9a2f48",
         "status": "under_review",
         "is_response_editable": false,
         "submission": {
          "submission_id": "dse_a1b2c3d4e5f6",
          "submission_status": "submitted",
          "trigger_source": "merchant_submit",
          "submitted_at": "2026-03-10T09:15:00.000Z"
         }
        }
       }
      }
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "requestBody": {
     "required": false,
     "description": "This endpoint does not require a request body. Submit all dispute evidence beforehand via the evidence update endpoint.",
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "description": "No request fields are accepted for this operation.",
        "additionalProperties": false,
        "properties": {}
       },
       "example": {}
      }
     }
    },
    "x-mint": {
     "href": "/api-reference/disputes/submit-dispute"
    }
   }
  },
  "/v1/customers": {
   "get": {
    "tags": [
     "Customers"
    ],
    "summary": "List customers",
    "description": "Returns a paginated list of your customers, most recent first. Pass `search` to filter by email or name. See [Pagination](/guides/pagination) for how to page through results. Requires the `customers:read` scope.",
    "operationId": "listCustomers",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 50,
       "minimum": 1,
       "maximum": 100
      }
     },
     {
      "name": "offset",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 0,
       "minimum": 0
      }
     },
     {
      "name": "search",
      "in": "query",
      "description": "Search by customer email or name.",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CustomerListResponse"
        },
        "example": {
         "items": [
          {
           "customer_id": "cust_1a2b3c4d5e6f7g8h",
           "email": "ada@example.com",
           "name": "Ada Lovelace",
           "metadata": {
            "tier": "vip"
           },
           "created_at": "2026-07-13T14:00:00.000Z",
           "updated_at": "2026-07-13T14:00:00.000Z"
          }
         ],
         "pagination": {
          "next_cursor": "cur_20",
          "prev_cursor": null,
          "has_more": true,
          "limit": 20,
          "offset": 0,
          "returned": 1,
          "total": 47
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    }
   },
   "post": {
    "tags": [
     "Customers"
    ],
    "summary": "Create a customer",
    "description": "Creates a customer. A customer groups a buyer's payments, subscriptions, and saved payment methods under one record. Only `email` is required. Requires the `customers:write` scope.",
    "operationId": "createCustomer",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateCustomerRequest"
       },
       "example": {
        "email": "jane@example.com",
        "metadata": {
         "plan": "pro"
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Customer created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CustomerDetailResponse"
        },
        "example": {
         "customer_id": "cust_1a2b3c4d5e6f7g8h",
         "email": "ada@example.com",
         "name": "Ada Lovelace",
         "phone_number": "+2348012345678",
         "metadata": {
          "tier": "vip"
         },
         "billing_address": {
          "line1": "40 Yaba Road",
          "line2": null,
          "city": "Lagos",
          "state": "Lagos",
          "postal_code": "101245",
          "country": "NG"
         },
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    }
   }
  },
  "/v1/customers/{customer_id}": {
   "get": {
    "tags": [
     "Customers"
    ],
    "summary": "Retrieve a customer",
    "description": "Retrieves a single customer by ID. Requires the `customers:read` scope.",
    "operationId": "getCustomer",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "customer_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "cust_1a2b3c4d5e6f"
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CustomerDetailResponse"
        },
        "example": {
         "customer_id": "cust_1a2b3c4d5e6f7g8h",
         "email": "ada@example.com",
         "name": "Ada Lovelace",
         "phone_number": "+2348012345678",
         "metadata": {
          "tier": "vip"
         },
         "billing_address": {
          "line1": "40 Yaba Road",
          "line2": null,
          "city": "Lagos",
          "state": "Lagos",
          "postal_code": "101245",
          "country": "NG"
         },
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    }
   },
   "patch": {
    "tags": [
     "Customers"
    ],
    "summary": "Update a customer",
    "description": "Updates a customer. Only the fields you send are changed. Requires the `customers:write` scope.",
    "operationId": "updateCustomer",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "customer_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "cust_1a2b3c4d5e6f"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/UpdateCustomerRequest"
       },
       "example": {
        "email": "jane.new@example.com",
        "metadata": {
         "plan": "enterprise"
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Customer updated",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CustomerDetailResponse"
        },
        "example": {
         "customer_id": "cust_1a2b3c4d5e6f7g8h",
         "email": "ada@example.com",
         "name": "Ada Lovelace",
         "phone_number": "+2348012345678",
         "metadata": {
          "tier": "vip"
         },
         "billing_address": {
          "line1": "40 Yaba Road",
          "line2": null,
          "city": "Lagos",
          "state": "Lagos",
          "postal_code": "101245",
          "country": "NG"
         },
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    }
   }
  },
  "/v1/customers/{customer_id}/portal-sessions": {
   "post": {
    "tags": [
     "Customer sessions"
    ],
    "summary": "Create a customer portal session",
    "description": "Creates a pre-authenticated customer portal session and returns the URL that opens it. The URL carries the session credential, so redirect the customer to it and do not log or share it. Sessions are short-lived; create a fresh one each time a customer asks to manage their billing. Requires the `customers:write` scope.",
    "operationId": "createCustomerPortalSession",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "customer_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "cust_1a2b3c4d5e6f"
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PortalSessionResponse"
        },
        "example": {
         "id": "psn_9f2c4a7b1d3e",
         "url": "https://portal.bachs.io/s/6Yc0nQpR2vX1sK7fLbA9tE"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     },
     "503": {
      "description": "Service Unavailable - The portal cannot issue sessions right now. Retry once; if it persists, contact support.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        },
        "example": {
         "detail": "The billing portal is not configured for this environment.",
         "error_code": "SERVICE_UNAVAILABLE"
        }
       }
      }
     }
    }
   }
  },
  "/v1/products": {
   "post": {
    "tags": [
     "Products"
    ],
    "summary": "Create a product",
    "description": "Creates a product with its pricing. Every product has a `price`; add a `billing_cycle` to make it recurring, or omit it for a one-time product. Sell products through checkout sessions and subscriptions. Requires the `products:write` scope.",
    "operationId": "createProduct",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateProductRequest"
       },
       "example": {
        "name": "Pro Plan",
        "description": "Monthly access to all Pro features.",
        "price": {
         "currency": "USD",
         "amount": "29.00",
         "currency_options": [
          {
           "currency": "NGN",
           "amount": "45000.00"
          }
         ]
        },
        "billing_cycle": {
         "interval": "month",
         "frequency": 1
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Product created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductResponse"
        },
        "example": {
         "id": "prod_1a2b3c4d5e6f7g8h",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Pro Plan",
         "description": "Full access, billed monthly.",
         "price": {
          "currency": "USD",
          "price_type": "fixed",
          "amount": "29.00",
          "preset_amount": null,
          "minimum_amount": null,
          "maximum_amount": null,
          "currency_options": []
         },
         "prices": [
          {
           "currency": "USD",
           "amount": "29.00",
           "minimum_amount": null,
           "maximum_amount": null,
           "is_default": true
          }
         ],
         "billing_cycle": {
          "interval": "month",
          "frequency": 1
         },
         "trial_period": null,
         "status": "active",
         "metadata": {
          "tier": "pro"
         },
         "media": [],
         "actor_id": "usr_abc123",
         "total_payments": 0,
         "total_amount": "0.00",
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z",
         "archived_at": null
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/ValidationError"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     }
    }
   },
   "get": {
    "tags": [
     "Products"
    ],
    "summary": "List products",
    "description": "Returns a paginated list of your products, most recent first. Archived products are excluded unless you pass `include_archived=true`. See [Pagination](/guides/pagination) for how to page through results. Requires the `products:read` scope.",
    "operationId": "listProducts",
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 20,
       "minimum": 1,
       "maximum": 100
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "include_archived",
      "in": "query",
      "description": "Include archived products in the results. Defaults to `false`.",
      "schema": {
       "type": "boolean",
       "default": false
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductListResponse"
        },
        "example": {
         "items": [
          {
           "id": "prod_1a2b3c4d5e6f7g8h",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Pro Plan",
           "description": "Full access, billed monthly.",
           "price": {
            "currency": "USD",
            "price_type": "fixed",
            "amount": "29.00",
            "preset_amount": null,
            "minimum_amount": null,
            "maximum_amount": null,
            "currency_options": []
           },
           "prices": [
            {
             "currency": "USD",
             "amount": "29.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": true
            }
           ],
           "billing_cycle": {
            "interval": "month",
            "frequency": 1
           },
           "trial_period": null,
           "status": "active",
           "metadata": {
            "tier": "pro"
           },
           "media": [],
           "actor_id": "usr_abc123",
           "total_payments": 0,
           "total_amount": "0.00",
           "created_at": "2026-07-13T14:00:00.000Z",
           "updated_at": "2026-07-13T14:00:00.000Z",
           "archived_at": null
          }
         ],
         "pagination": {
          "next_cursor": "cur_20",
          "prev_cursor": null,
          "has_more": true,
          "limit": 20,
          "offset": 0,
          "returned": 1,
          "total": 47
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     }
    }
   }
  },
  "/v1/products/{product_id}": {
   "get": {
    "tags": [
     "Products"
    ],
    "summary": "Retrieve a product",
    "description": "Retrieves a single product by its ID. Requires the `products:read` scope.",
    "operationId": "getProduct",
    "parameters": [
     {
      "name": "product_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "prod_1a2b3c4d5e6f"
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductResponse"
        },
        "example": {
         "id": "prod_1a2b3c4d5e6f7g8h",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Pro Plan",
         "description": "Full access, billed monthly.",
         "price": {
          "currency": "USD",
          "price_type": "fixed",
          "amount": "29.00",
          "preset_amount": null,
          "minimum_amount": null,
          "maximum_amount": null,
          "currency_options": []
         },
         "prices": [
          {
           "currency": "USD",
           "amount": "29.00",
           "minimum_amount": null,
           "maximum_amount": null,
           "is_default": true
          }
         ],
         "billing_cycle": {
          "interval": "month",
          "frequency": 1
         },
         "trial_period": null,
         "status": "active",
         "metadata": {
          "tier": "pro"
         },
         "media": [],
         "actor_id": "usr_abc123",
         "total_payments": 0,
         "total_amount": "0.00",
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z",
         "archived_at": null
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   },
   "patch": {
    "tags": [
     "Products"
    ],
    "summary": "Update a product",
    "description": "Updates a product. You can change its name, description, metadata, media, price, and (if not yet set) its `billing_cycle` and `trial_period`. A `billing_cycle` is immutable once set, so a recurring product's interval cannot be changed. Create a new product for a different cadence. Requires the `products:write` scope.",
    "operationId": "updateProduct",
    "parameters": [
     {
      "name": "product_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/UpdateProductRequest"
       },
       "example": {
        "description": "Updated description.",
        "metadata": {
         "tier": "pro"
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Product updated",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductResponse"
        },
        "example": {
         "id": "prod_1a2b3c4d5e6f7g8h",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Pro Plan",
         "description": "Updated description.",
         "price": {
          "currency": "USD",
          "price_type": "fixed",
          "amount": "29.00",
          "preset_amount": null,
          "minimum_amount": null,
          "maximum_amount": null,
          "currency_options": []
         },
         "prices": [
          {
           "currency": "USD",
           "amount": "29.00",
           "minimum_amount": null,
           "maximum_amount": null,
           "is_default": true
          }
         ],
         "billing_cycle": {
          "interval": "month",
          "frequency": 1
         },
         "trial_period": null,
         "status": "active",
         "metadata": {
          "tier": "pro"
         },
         "media": [],
         "actor_id": "usr_abc123",
         "total_payments": 0,
         "total_amount": "0.00",
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z",
         "archived_at": null
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/ValidationError"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/products/{product_id}/archive": {
   "post": {
    "tags": [
     "Products"
    ],
    "summary": "Archive a product",
    "description": "Archives a product so it can no longer be used in new checkouts or subscriptions. Existing subscriptions keep billing. This is idempotent: archiving an already-archived product succeeds. Reverse it with [Unarchive Product](/api-reference/products/unarchive-product). Requires the `products:write` scope.",
    "operationId": "archiveProduct",
    "parameters": [
     {
      "name": "product_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Product archived",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductResponse"
        },
        "example": {
         "id": "prod_1a2b3c4d5e6f7g8h",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Pro Plan",
         "description": "Full access, billed monthly.",
         "price": {
          "currency": "USD",
          "price_type": "fixed",
          "amount": "29.00",
          "preset_amount": null,
          "minimum_amount": null,
          "maximum_amount": null,
          "currency_options": []
         },
         "prices": [
          {
           "currency": "USD",
           "amount": "29.00",
           "minimum_amount": null,
           "maximum_amount": null,
           "is_default": true
          }
         ],
         "billing_cycle": {
          "interval": "month",
          "frequency": 1
         },
         "trial_period": null,
         "status": "archived",
         "metadata": {
          "tier": "pro"
         },
         "media": [],
         "actor_id": "usr_abc123",
         "total_payments": 0,
         "total_amount": "0.00",
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z",
         "archived_at": "2026-07-13T14:30:00.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/products/{product_id}/unarchive": {
   "post": {
    "tags": [
     "Products"
    ],
    "summary": "Unarchive a product",
    "description": "Restores an archived product to active status so it can be used again. This is idempotent. Requires the `products:write` scope.",
    "operationId": "unarchiveProduct",
    "parameters": [
     {
      "name": "product_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Product unarchived",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductResponse"
        },
        "example": {
         "id": "prod_1a2b3c4d5e6f7g8h",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Pro Plan",
         "description": "Full access, billed monthly.",
         "price": {
          "currency": "USD",
          "price_type": "fixed",
          "amount": "29.00",
          "preset_amount": null,
          "minimum_amount": null,
          "maximum_amount": null,
          "currency_options": []
         },
         "prices": [
          {
           "currency": "USD",
           "amount": "29.00",
           "minimum_amount": null,
           "maximum_amount": null,
           "is_default": true
          }
         ],
         "billing_cycle": {
          "interval": "month",
          "frequency": 1
         },
         "trial_period": null,
         "status": "active",
         "metadata": {
          "tier": "pro"
         },
         "media": [],
         "actor_id": "usr_abc123",
         "total_payments": 0,
         "total_amount": "0.00",
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z",
         "archived_at": null
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/product-groups": {
   "post": {
    "tags": [
     "Product Groups"
    ],
    "summary": "Create Product Group",
    "description": "Bundle two or more products into a group for multi-plan checkout. Requires `PRODUCTS_WRITE` scope.",
    "operationId": "createProductGroup",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateProductGroupRequest"
       },
       "example": {
        "name": "Pro Plan Billing Options",
        "product_ids": [
         "prod_4b91c2e7d3a85f60b1c9",
         "prod_7e2a9c4f1b60d38a5e21"
        ]
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Product group created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductGroupResponse"
        },
        "example": {
         "id": "pgrp_9c4d1e7a2b8f6035a1d4",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Pro Plan Billing Options",
         "products": [
          {
           "id": "prod_4b91c2e7d3a85f60b1c9",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Pro Monthly",
           "description": "Full access, billed every month.",
           "price": {
            "currency": "USD",
            "price_type": "fixed",
            "amount": "29.00",
            "preset_amount": null,
            "minimum_amount": null,
            "maximum_amount": null,
            "currency_options": [
             {
              "currency": "NGN",
              "amount": "43500.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null
             }
            ]
           },
           "prices": [
            {
             "currency": "USD",
             "amount": "29.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": true
            },
            {
             "currency": "NGN",
             "amount": "43500.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": false
            }
           ],
           "billing_cycle": {
            "interval": "month",
            "frequency": 1
           },
           "trial_period": null,
           "status": "active",
           "metadata": {
            "tier": "pro"
           },
           "media": [],
           "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
           "total_payments": 0,
           "total_amount": "0.00",
           "created_at": "2026-07-13T13:41:02.000Z",
           "updated_at": "2026-07-13T13:41:02.000Z",
           "archived_at": null
          },
          {
           "id": "prod_7e2a9c4f1b60d38a5e21",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Pro Yearly",
           "description": "Full access, billed once a year at two months off.",
           "price": {
            "currency": "USD",
            "price_type": "fixed",
            "amount": "290.00",
            "preset_amount": null,
            "minimum_amount": null,
            "maximum_amount": null,
            "currency_options": [
             {
              "currency": "NGN",
              "amount": "435000.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null
             }
            ]
           },
           "prices": [
            {
             "currency": "USD",
             "amount": "290.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": true
            },
            {
             "currency": "NGN",
             "amount": "435000.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": false
            }
           ],
           "billing_cycle": {
            "interval": "year",
            "frequency": 1
           },
           "trial_period": {
            "interval": "day",
            "frequency": 14
           },
           "status": "active",
           "metadata": {
            "tier": "pro"
           },
           "media": [],
           "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
           "total_payments": 0,
           "total_amount": "0.00",
           "created_at": "2026-07-13T13:44:19.000Z",
           "updated_at": "2026-07-13T13:44:19.000Z",
           "archived_at": null
          }
         ],
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/ValidationError"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     }
    }
   },
   "get": {
    "tags": [
     "Product Groups"
    ],
    "summary": "List Product Groups",
    "description": "Return a paginated list of product groups. Requires `PRODUCTS_READ` scope.",
    "operationId": "listProductGroups",
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 20,
       "minimum": 1,
       "maximum": 100
      }
     },
     {
      "name": "cursor",
      "in": "query",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductGroupListResponse"
        },
        "example": {
         "items": [
          {
           "id": "pgrp_9c4d1e7a2b8f6035a1d4",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Pro Plan Billing Options",
           "products": [
            {
             "id": "prod_4b91c2e7d3a85f60b1c9",
             "organization_id": "acct_7KpQ2mNv4XbR9dLc",
             "name": "Pro Monthly",
             "description": "Full access, billed every month.",
             "price": {
              "currency": "USD",
              "price_type": "fixed",
              "amount": "29.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null,
              "currency_options": [
               {
                "currency": "NGN",
                "amount": "43500.00",
                "preset_amount": null,
                "minimum_amount": null,
                "maximum_amount": null
               }
              ]
             },
             "prices": [
              {
               "currency": "USD",
               "amount": "29.00",
               "minimum_amount": null,
               "maximum_amount": null,
               "is_default": true
              },
              {
               "currency": "NGN",
               "amount": "43500.00",
               "minimum_amount": null,
               "maximum_amount": null,
               "is_default": false
              }
             ],
             "billing_cycle": {
              "interval": "month",
              "frequency": 1
             },
             "trial_period": null,
             "status": "active",
             "metadata": {
              "tier": "pro"
             },
             "media": [],
             "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
             "total_payments": 18,
             "total_amount": "522.00",
             "created_at": "2026-07-13T13:41:02.000Z",
             "updated_at": "2026-07-13T13:41:02.000Z",
             "archived_at": null
            },
            {
             "id": "prod_7e2a9c4f1b60d38a5e21",
             "organization_id": "acct_7KpQ2mNv4XbR9dLc",
             "name": "Pro Yearly",
             "description": "Full access, billed once a year at two months off.",
             "price": {
              "currency": "USD",
              "price_type": "fixed",
              "amount": "290.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null,
              "currency_options": [
               {
                "currency": "NGN",
                "amount": "435000.00",
                "preset_amount": null,
                "minimum_amount": null,
                "maximum_amount": null
               }
              ]
             },
             "prices": [
              {
               "currency": "USD",
               "amount": "290.00",
               "minimum_amount": null,
               "maximum_amount": null,
               "is_default": true
              },
              {
               "currency": "NGN",
               "amount": "435000.00",
               "minimum_amount": null,
               "maximum_amount": null,
               "is_default": false
              }
             ],
             "billing_cycle": {
              "interval": "year",
              "frequency": 1
             },
             "trial_period": {
              "interval": "day",
              "frequency": 14
             },
             "status": "active",
             "metadata": {
              "tier": "pro"
             },
             "media": [],
             "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
             "total_payments": 4,
             "total_amount": "1160.00",
             "created_at": "2026-07-13T13:44:19.000Z",
             "updated_at": "2026-07-13T13:44:19.000Z",
             "archived_at": null
            }
           ],
           "created_at": "2026-07-13T14:00:00.000Z",
           "updated_at": "2026-07-13T14:00:00.000Z"
          },
          {
           "id": "pgrp_1f80a63c9d24e5b7c0a8",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Starter Billing Options",
           "products": [
            {
             "id": "prod_0d5c8a12e7b93f461ca2",
             "organization_id": "acct_7KpQ2mNv4XbR9dLc",
             "name": "Starter Monthly",
             "description": "Core features for a single seat, billed every month.",
             "price": {
              "currency": "USD",
              "price_type": "fixed",
              "amount": "9.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null,
              "currency_options": []
             },
             "prices": [
              {
               "currency": "USD",
               "amount": "9.00",
               "minimum_amount": null,
               "maximum_amount": null,
               "is_default": true
              }
             ],
             "billing_cycle": {
              "interval": "month",
              "frequency": 1
             },
             "trial_period": null,
             "status": "active",
             "metadata": {
              "tier": "starter"
             },
             "media": [],
             "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
             "total_payments": 61,
             "total_amount": "549.00",
             "created_at": "2026-06-02T10:15:30.000Z",
             "updated_at": "2026-06-02T10:15:30.000Z",
             "archived_at": null
            }
           ],
           "created_at": "2026-06-02T10:20:00.000Z",
           "updated_at": "2026-06-02T10:20:00.000Z"
          }
         ],
         "pagination": {
          "next_cursor": null,
          "prev_cursor": null,
          "has_more": false,
          "limit": 20,
          "offset": 0,
          "returned": 2,
          "total": 2
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     }
    }
   }
  },
  "/v1/product-groups/{group_id}": {
   "get": {
    "tags": [
     "Product Groups"
    ],
    "summary": "Get Product Group",
    "description": "Fetch a product group and its member products. Requires `PRODUCTS_READ` scope.",
    "operationId": "getProductGroup",
    "parameters": [
     {
      "name": "group_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "include_archived",
      "in": "query",
      "schema": {
       "type": "boolean",
       "default": false
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Success",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductGroupResponse"
        },
        "example": {
         "id": "pgrp_9c4d1e7a2b8f6035a1d4",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Pro Plan Billing Options",
         "products": [
          {
           "id": "prod_4b91c2e7d3a85f60b1c9",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Pro Monthly",
           "description": "Full access, billed every month.",
           "price": {
            "currency": "USD",
            "price_type": "fixed",
            "amount": "29.00",
            "preset_amount": null,
            "minimum_amount": null,
            "maximum_amount": null,
            "currency_options": [
             {
              "currency": "NGN",
              "amount": "43500.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null
             }
            ]
           },
           "prices": [
            {
             "currency": "USD",
             "amount": "29.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": true
            },
            {
             "currency": "NGN",
             "amount": "43500.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": false
            }
           ],
           "billing_cycle": {
            "interval": "month",
            "frequency": 1
           },
           "trial_period": null,
           "status": "active",
           "metadata": {
            "tier": "pro"
           },
           "media": [],
           "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
           "total_payments": 18,
           "total_amount": "522.00",
           "created_at": "2026-07-13T13:41:02.000Z",
           "updated_at": "2026-07-13T13:41:02.000Z",
           "archived_at": null
          },
          {
           "id": "prod_7e2a9c4f1b60d38a5e21",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Pro Yearly",
           "description": "Full access, billed once a year at two months off.",
           "price": {
            "currency": "USD",
            "price_type": "fixed",
            "amount": "290.00",
            "preset_amount": null,
            "minimum_amount": null,
            "maximum_amount": null,
            "currency_options": [
             {
              "currency": "NGN",
              "amount": "435000.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null
             }
            ]
           },
           "prices": [
            {
             "currency": "USD",
             "amount": "290.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": true
            },
            {
             "currency": "NGN",
             "amount": "435000.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": false
            }
           ],
           "billing_cycle": {
            "interval": "year",
            "frequency": 1
           },
           "trial_period": {
            "interval": "day",
            "frequency": 14
           },
           "status": "active",
           "metadata": {
            "tier": "pro"
           },
           "media": [],
           "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
           "total_payments": 4,
           "total_amount": "1160.00",
           "created_at": "2026-07-13T13:44:19.000Z",
           "updated_at": "2026-07-13T13:44:19.000Z",
           "archived_at": null
          }
         ],
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-13T14:00:00.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   },
   "patch": {
    "tags": [
     "Product Groups"
    ],
    "summary": "Update Product Group",
    "description": "Rename the group and/or replace its product membership. Requires `PRODUCTS_WRITE` scope.",
    "operationId": "updateProductGroup",
    "parameters": [
     {
      "name": "group_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/UpdateProductGroupRequest"
       },
       "example": {
        "name": "Pro Plan Billing Options (2026)",
        "product_ids": [
         "prod_7e2a9c4f1b60d38a5e21",
         "prod_4b91c2e7d3a85f60b1c9"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Product group updated",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductGroupResponse"
        },
        "example": {
         "id": "pgrp_9c4d1e7a2b8f6035a1d4",
         "organization_id": "acct_7KpQ2mNv4XbR9dLc",
         "name": "Pro Plan Billing Options (2026)",
         "products": [
          {
           "id": "prod_7e2a9c4f1b60d38a5e21",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Pro Yearly",
           "description": "Full access, billed once a year at two months off.",
           "price": {
            "currency": "USD",
            "price_type": "fixed",
            "amount": "290.00",
            "preset_amount": null,
            "minimum_amount": null,
            "maximum_amount": null,
            "currency_options": [
             {
              "currency": "NGN",
              "amount": "435000.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null
             }
            ]
           },
           "prices": [
            {
             "currency": "USD",
             "amount": "290.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": true
            },
            {
             "currency": "NGN",
             "amount": "435000.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": false
            }
           ],
           "billing_cycle": {
            "interval": "year",
            "frequency": 1
           },
           "trial_period": {
            "interval": "day",
            "frequency": 14
           },
           "status": "active",
           "metadata": {
            "tier": "pro"
           },
           "media": [],
           "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
           "total_payments": 4,
           "total_amount": "1160.00",
           "created_at": "2026-07-13T13:44:19.000Z",
           "updated_at": "2026-07-13T13:44:19.000Z",
           "archived_at": null
          },
          {
           "id": "prod_4b91c2e7d3a85f60b1c9",
           "organization_id": "acct_7KpQ2mNv4XbR9dLc",
           "name": "Pro Monthly",
           "description": "Full access, billed every month.",
           "price": {
            "currency": "USD",
            "price_type": "fixed",
            "amount": "29.00",
            "preset_amount": null,
            "minimum_amount": null,
            "maximum_amount": null,
            "currency_options": [
             {
              "currency": "NGN",
              "amount": "43500.00",
              "preset_amount": null,
              "minimum_amount": null,
              "maximum_amount": null
             }
            ]
           },
           "prices": [
            {
             "currency": "USD",
             "amount": "29.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": true
            },
            {
             "currency": "NGN",
             "amount": "43500.00",
             "minimum_amount": null,
             "maximum_amount": null,
             "is_default": false
            }
           ],
           "billing_cycle": {
            "interval": "month",
            "frequency": 1
           },
           "trial_period": null,
           "status": "active",
           "metadata": {
            "tier": "pro"
           },
           "media": [],
           "actor_id": "usr_3c8e0b1f9d244a7c8e5f6b2a1d907c43",
           "total_payments": 18,
           "total_amount": "522.00",
           "created_at": "2026-07-13T13:41:02.000Z",
           "updated_at": "2026-07-13T13:41:02.000Z",
           "archived_at": null
          }
         ],
         "created_at": "2026-07-13T14:00:00.000Z",
         "updated_at": "2026-07-14T08:12:44.930Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/ValidationError"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   },
   "delete": {
    "tags": [
     "Product Groups"
    ],
    "summary": "Delete Product Group",
    "description": "Permanently delete a product group. Member products are not affected. Requires `PRODUCTS_WRITE` scope.",
    "operationId": "deleteProductGroup",
    "parameters": [
     {
      "name": "group_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "204": {
      "description": "Group deleted"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/utilities/uploads": {
   "post": {
    "tags": [
     "Media"
    ],
    "summary": "Upload a file",
    "description": "Upload a file and receive an `upload_id`. Pass this ID in the `media` array when creating or updating a product.\n\nFiles must be sent as `multipart/form-data`. Maximum size is **20 MB**.",
    "operationId": "createUpload",
    "requestBody": {
     "required": true,
     "content": {
      "multipart/form-data": {
       "schema": {
        "type": "object",
        "required": [
         "file"
        ],
        "properties": {
         "file": {
          "type": "string",
          "format": "binary",
          "description": "The file to upload. Maximum 20 MB."
         },
         "scope": {
          "type": "string",
          "default": "general",
          "pattern": "^[a-z0-9_-]{1,64}$",
          "description": "Logical grouping for the upload. Use `product-media` for product images. Defaults to `general`."
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Upload created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/UploadResponse"
        },
        "example": {
         "upload_id": "upl_4f3e2d1c",
         "file_name": "product-hero.png",
         "mime_type": "image/png",
         "file_size_bytes": 204800,
         "url": "https://cdn.bachs.io/uploads/upl_4f3e2d1c/product-hero.png",
         "linked_resource_type": null,
         "linked_resource_id": null,
         "created_at": "2026-01-24T12:00:00.000Z",
         "updated_at": "2026-01-24T12:00:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/ValidationError"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    }
   }
  },
  "/v1/utilities/uploads/{upload_id}": {
   "get": {
    "tags": [
     "Media"
    ],
    "summary": "Retrieve an upload",
    "description": "Retrieve metadata for a previously created upload by its ID.",
    "operationId": "getUpload",
    "parameters": [
     {
      "name": "upload_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "upl_4f3e2d1c"
     }
    ],
    "responses": {
     "200": {
      "description": "Upload metadata",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/UploadResponse"
        },
        "example": {
         "upload_id": "upl_4f3e2d1c9b8a7605f4e3",
         "file_name": "pro-plan-hero.png",
         "mime_type": "image/png",
         "file_size_bytes": 204800,
         "url": "https://cdn.bachs.io/uploads/upl_4f3e2d1c9b8a7605f4e3/pro-plan-hero.png",
         "linked_resource_type": "product",
         "linked_resource_id": "prod_4b91c2e7d3a85f60b1c9",
         "created_at": "2026-07-13T13:40:11.000Z",
         "updated_at": "2026-07-13T13:41:02.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   },
   "delete": {
    "tags": [
     "Media"
    ],
    "summary": "Delete an upload",
    "description": "Delete an upload that has not yet been linked to any resource. Returns a `409` if the upload is already attached to a product.",
    "operationId": "deleteUpload",
    "parameters": [
     {
      "name": "upload_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "upl_4f3e2d1c"
     }
    ],
    "responses": {
     "200": {
      "description": "Upload deleted",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/UploadDeleteResponse"
        },
        "example": {
         "upload_id": "upl_4f3e2d1c",
         "deleted": true
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    }
   }
  },
  "/v1/checkout-sessions/{checkout_id}": {
   "get": {
    "tags": [
     "Checkout Sessions"
    ],
    "summary": "Retrieve a checkout session",
    "description": "Retrieve the details of a checkout session by its ID, including resolved product line items and charge information.\n\nThe `charge` field is `null` while the session is `OPEN` and populated once the customer submits a payment.\n\nRequires `payments:read` scope.",
    "operationId": "getCheckoutSession",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "checkout_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The checkout ID returned when the session was created.",
      "example": "chk_1M2N3o4P5q6R7s8T"
     }
    ],
    "responses": {
     "200": {
      "description": "Checkout session retrieved successfully.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CheckoutSessionApiResponse"
        },
        "example": {
         "checkout_id": "chk_1M2N3o4P5q6R7s8T",
         "status": "completed",
         "recurring": null,
         "payment_status": "succeeded",
         "source_type": "CHECKOUT_SESSION",
         "amount": "50.00",
         "currency": "USD",
         "reference": "order_9876",
         "charge": {
          "payment_id": "pay_1a2b3c4d5e",
          "billing_reason": "purchase",
          "status": "succeeded",
          "amount": "29.00",
          "currency": "USD",
          "fee_usd": "0.59"
         },
         "payment_method": "CARD",
         "customer": {
          "id": "cust_1a2b3c4d5e6f",
          "email": "jane@example.com",
          "name": "Jane Doe"
         },
         "customer_details": {
          "email": "jane@example.com",
          "name": "Jane Doe"
         },
         "success_url": "https://yourapp.com/success",
         "cancel_url": "https://yourapp.com/cancel",
         "products": [
          {
           "product_id": "prod_abc123",
           "product_name": "Premium Plan",
           "quantity": 1,
           "unit_amount": "50.00",
           "currency": "USD",
           "price_type": "fixed",
           "minimum_amount": null,
           "maximum_amount": null,
           "line_total": "50.00"
          }
         ],
         "billing_currency": "NGN",
         "session_mode": "CART",
         "metadata": {
          "order_id": "ORD-9876"
         },
         "created_at": "2026-01-24T14:30:00.000Z",
         "expires_at": "2026-01-24T15:30:00.000Z",
         "completed_at": "2026-01-24T14:35:00.000Z",
         "updated_at": "2026-01-24T14:35:00.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    },
    "x-mint": {
     "href": "/api-reference/checkout-sessions/get-checkout-session"
    }
   }
  },
  "/v1/subscriptions": {
   "get": {
    "tags": [
     "Subscriptions"
    ],
    "summary": "List subscriptions",
    "description": "List subscriptions for your account, newest first. Filter by customer or status.",
    "operationId": "listSubscriptions",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "default": 50,
       "minimum": 1,
       "maximum": 100
      }
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "default": 0,
       "minimum": 0
      }
     },
     {
      "name": "customer_id",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Only subscriptions for this customer (cust_...)."
     },
     {
      "name": "status",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "trialing",
        "active",
        "past_due",
        "unpaid",
        "canceled"
       ]
      },
      "description": "Only subscriptions in this status."
     }
    ],
    "responses": {
     "200": {
      "description": "A page of subscriptions",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SubscriptionListResponse"
        },
        "example": {
         "items": [
          {
           "id": "sub_1a2b3c4d5e6f",
           "payment_method_id": "pm_7h8i9j0k",
           "status": "active",
           "collection_method": "charge_automatically",
           "currency": "USD",
           "amount": "10.00",
           "billing_cycle": {
            "interval": "month",
            "frequency": 1
           },
           "quantity": 1,
           "current_period_start": "2026-07-13T12:00:00Z",
           "current_period_end": "2026-08-13T12:00:00Z",
           "previously_billed_at": "2026-07-13T12:00:00Z",
           "next_billed_at": "2026-08-13T12:00:00Z",
           "trial_end": null,
           "cancel_at_period_end": false,
           "canceled_at": null,
           "created_at": "2026-07-13T12:00:00Z",
           "product": {
            "id": "prod_abc123",
            "name": "Pro plan",
            "description": "Everything in Pro.",
            "status": "active",
            "billing_cycle": {
             "interval": "month",
             "frequency": 1
            },
            "trial_period": null,
            "created_at": "2026-07-01T09:00:00Z",
            "updated_at": "2026-07-01T09:00:00Z"
           },
           "items": [
            {
             "id": "si_11aa22bb",
             "status": "active",
             "quantity": 1,
             "recurring": true,
             "price_type": "fixed",
             "unit_amount": "10.00",
             "currency": "USD",
             "previously_billed_at": "2026-07-13T12:00:00Z",
             "next_billed_at": "2026-08-13T12:00:00Z",
             "price": {
              "id": "price_pro_usd",
              "product_id": "prod_abc123",
              "price_type": "fixed",
              "currency": "USD",
              "unit_amount": "10.00",
              "billing_cycle": {
               "interval": "month",
               "frequency": 1
              },
              "trial_period": null,
              "seat_tiers": null,
              "is_archived": false,
              "created_at": "2026-07-01T09:00:00Z",
              "updated_at": "2026-07-01T09:00:00Z"
             },
             "product": {
              "id": "prod_abc123",
              "name": "Pro plan",
              "status": "active",
              "billing_cycle": {
               "interval": "month",
               "frequency": 1
              },
              "trial_period": null,
              "created_at": "2026-07-01T09:00:00Z",
              "updated_at": "2026-07-01T09:00:00Z"
             },
             "created_at": "2026-07-13T12:00:00Z",
             "updated_at": "2026-07-13T12:00:00Z"
            }
           ],
           "customer": {
            "customer_id": "cust_xyz789",
            "email": "customer@example.com",
            "name": "Jane Doe",
            "phone_number": "+2348012345678",
            "metadata": {},
            "created_at": "2026-07-01T09:00:00Z",
            "updated_at": "2026-07-01T09:00:00Z"
           }
          }
         ],
         "pagination": {
          "next_cursor": null,
          "prev_cursor": null,
          "has_more": false,
          "limit": 50,
          "offset": 0,
          "returned": 1,
          "total": 1
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/subscriptions/list-subscriptions"
    }
   }
  },
  "/v1/subscriptions/{subscription_id}": {
   "get": {
    "tags": [
     "Subscriptions"
    ],
    "summary": "Retrieve a subscription",
    "description": "Retrieve a single subscription with its product, price, items, and billing dates.",
    "operationId": "getSubscription",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "subscription_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The subscription's public ID (sub_...)."
     }
    ],
    "responses": {
     "200": {
      "description": "The subscription",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SubscriptionResponse"
        },
        "example": {
         "id": "sub_1a2b3c4d5e6f",
         "payment_method_id": "pm_7h8i9j0k",
         "status": "active",
         "collection_method": "charge_automatically",
         "currency": "USD",
         "amount": "10.00",
         "billing_cycle": {
          "interval": "month",
          "frequency": 1
         },
         "quantity": 1,
         "current_period_start": "2026-07-13T12:00:00Z",
         "current_period_end": "2026-08-13T12:00:00Z",
         "previously_billed_at": "2026-07-13T12:00:00Z",
         "next_billed_at": "2026-08-13T12:00:00Z",
         "trial_end": null,
         "cancel_at_period_end": false,
         "canceled_at": null,
         "created_at": "2026-07-13T12:00:00Z",
         "product": {
          "id": "prod_abc123",
          "name": "Pro plan",
          "description": "Everything in Pro.",
          "status": "active",
          "billing_cycle": {
           "interval": "month",
           "frequency": 1
          },
          "trial_period": null,
          "created_at": "2026-07-01T09:00:00Z",
          "updated_at": "2026-07-01T09:00:00Z"
         },
         "items": [
          {
           "id": "si_11aa22bb",
           "status": "active",
           "quantity": 1,
           "recurring": true,
           "price_type": "fixed",
           "unit_amount": "10.00",
           "currency": "USD",
           "previously_billed_at": "2026-07-13T12:00:00Z",
           "next_billed_at": "2026-08-13T12:00:00Z",
           "price": {
            "id": "price_pro_usd",
            "product_id": "prod_abc123",
            "price_type": "fixed",
            "currency": "USD",
            "unit_amount": "10.00",
            "billing_cycle": {
             "interval": "month",
             "frequency": 1
            },
            "trial_period": null,
            "seat_tiers": null,
            "is_archived": false,
            "created_at": "2026-07-01T09:00:00Z",
            "updated_at": "2026-07-01T09:00:00Z"
           },
           "product": {
            "id": "prod_abc123",
            "name": "Pro plan",
            "status": "active",
            "billing_cycle": {
             "interval": "month",
             "frequency": 1
            },
            "trial_period": null,
            "created_at": "2026-07-01T09:00:00Z",
            "updated_at": "2026-07-01T09:00:00Z"
           },
           "created_at": "2026-07-13T12:00:00Z",
           "updated_at": "2026-07-13T12:00:00Z"
          }
         ],
         "customer": {
          "customer_id": "cust_xyz789",
          "email": "customer@example.com",
          "name": "Jane Doe",
          "phone_number": "+2348012345678",
          "metadata": {},
          "created_at": "2026-07-01T09:00:00Z",
          "updated_at": "2026-07-01T09:00:00Z"
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/subscriptions/get-subscription"
    }
   },
   "patch": {
    "tags": [
     "Subscriptions"
    ],
    "summary": "Update a subscription",
    "description": "Change a subscription. Send exactly one intent: change the plan, move a trial, or change the payment method. Returns the full updated subscription.",
    "operationId": "updateSubscription",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "subscription_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The subscription's public ID (sub_...)."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/UpdateSubscriptionRequest"
       },
       "examples": {
        "Change the plan": {
         "value": {
          "product_id": "prod_premium",
          "proration_behavior": "invoice_now"
         }
        },
        "Add or extend a trial": {
         "value": {
          "trial_end": "2026-08-10T12:00:00Z"
         }
        },
        "End the trial now": {
         "value": {
          "trial_end": "2026-07-13T12:00:00Z"
         }
        },
        "Update the payment method": {
         "value": {
          "payment_method_id": "pm_new456"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The updated subscription",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SubscriptionResponse"
        },
        "example": {
         "id": "sub_1a2b3c4d5e6f",
         "payment_method_id": "pm_7h8i9j0k",
         "status": "active",
         "collection_method": "charge_automatically",
         "currency": "USD",
         "amount": "10.00",
         "billing_cycle": {
          "interval": "month",
          "frequency": 1
         },
         "quantity": 1,
         "current_period_start": "2026-07-13T12:00:00Z",
         "current_period_end": "2026-08-13T12:00:00Z",
         "previously_billed_at": "2026-07-13T12:00:00Z",
         "next_billed_at": "2026-08-13T12:00:00Z",
         "trial_end": null,
         "cancel_at_period_end": false,
         "canceled_at": null,
         "created_at": "2026-07-13T12:00:00Z",
         "product": {
          "id": "prod_abc123",
          "name": "Pro plan",
          "description": "Everything in Pro.",
          "status": "active",
          "billing_cycle": {
           "interval": "month",
           "frequency": 1
          },
          "trial_period": null,
          "created_at": "2026-07-01T09:00:00Z",
          "updated_at": "2026-07-01T09:00:00Z"
         },
         "items": [
          {
           "id": "si_11aa22bb",
           "status": "active",
           "quantity": 1,
           "recurring": true,
           "price_type": "fixed",
           "unit_amount": "10.00",
           "currency": "USD",
           "previously_billed_at": "2026-07-13T12:00:00Z",
           "next_billed_at": "2026-08-13T12:00:00Z",
           "price": {
            "id": "price_pro_usd",
            "product_id": "prod_abc123",
            "price_type": "fixed",
            "currency": "USD",
            "unit_amount": "10.00",
            "billing_cycle": {
             "interval": "month",
             "frequency": 1
            },
            "trial_period": null,
            "seat_tiers": null,
            "is_archived": false,
            "created_at": "2026-07-01T09:00:00Z",
            "updated_at": "2026-07-01T09:00:00Z"
           },
           "product": {
            "id": "prod_abc123",
            "name": "Pro plan",
            "status": "active",
            "billing_cycle": {
             "interval": "month",
             "frequency": 1
            },
            "trial_period": null,
            "created_at": "2026-07-01T09:00:00Z",
            "updated_at": "2026-07-01T09:00:00Z"
           },
           "created_at": "2026-07-13T12:00:00Z",
           "updated_at": "2026-07-13T12:00:00Z"
          }
         ],
         "customer": {
          "customer_id": "cust_xyz789",
          "email": "customer@example.com",
          "name": "Jane Doe",
          "phone_number": "+2348012345678",
          "metadata": {},
          "created_at": "2026-07-01T09:00:00Z",
          "updated_at": "2026-07-01T09:00:00Z"
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/subscriptions/update-subscription"
    }
   },
   "delete": {
    "tags": [
     "Subscriptions"
    ],
    "summary": "Cancel a subscription",
    "description": "Cancel a subscription immediately, or at the end of the current period with cancel_at_period_end. Returns the updated subscription.",
    "operationId": "cancelSubscription",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "subscription_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The subscription's public ID (sub_...)."
     }
    ],
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CancelSubscriptionRequest"
       },
       "examples": {
        "Cancel at period end": {
         "value": {
          "cancel_at_period_end": true,
          "reason": "Customer requested"
         }
        },
        "Cancel immediately": {
         "value": {
          "cancel_at_period_end": false
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The canceled (or scheduled-to-cancel) subscription",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SubscriptionResponse"
        },
        "example": {
         "id": "sub_1a2b3c4d5e6f",
         "payment_method_id": "pm_7h8i9j0k",
         "status": "canceled",
         "collection_method": "charge_automatically",
         "currency": "USD",
         "amount": "10.00",
         "billing_cycle": {
          "interval": "month",
          "frequency": 1
         },
         "quantity": 1,
         "current_period_start": "2026-07-13T12:00:00Z",
         "current_period_end": "2026-08-13T12:00:00Z",
         "previously_billed_at": "2026-07-13T12:00:00Z",
         "next_billed_at": null,
         "trial_end": null,
         "cancel_at_period_end": false,
         "canceled_at": "2026-09-01T09:00:00Z",
         "created_at": "2026-07-13T12:00:00Z",
         "product": {
          "id": "prod_abc123",
          "name": "Pro plan",
          "description": "Everything in Pro.",
          "status": "active",
          "billing_cycle": {
           "interval": "month",
           "frequency": 1
          },
          "trial_period": null,
          "created_at": "2026-07-01T09:00:00Z",
          "updated_at": "2026-07-01T09:00:00Z"
         },
         "items": [
          {
           "id": "si_11aa22bb",
           "status": "active",
           "quantity": 1,
           "recurring": true,
           "price_type": "fixed",
           "unit_amount": "10.00",
           "currency": "USD",
           "previously_billed_at": "2026-07-13T12:00:00Z",
           "next_billed_at": "2026-08-13T12:00:00Z",
           "price": {
            "id": "price_pro_usd",
            "product_id": "prod_abc123",
            "price_type": "fixed",
            "currency": "USD",
            "unit_amount": "10.00",
            "billing_cycle": {
             "interval": "month",
             "frequency": 1
            },
            "trial_period": null,
            "seat_tiers": null,
            "is_archived": false,
            "created_at": "2026-07-01T09:00:00Z",
            "updated_at": "2026-07-01T09:00:00Z"
           },
           "product": {
            "id": "prod_abc123",
            "name": "Pro plan",
            "status": "active",
            "billing_cycle": {
             "interval": "month",
             "frequency": 1
            },
            "trial_period": null,
            "created_at": "2026-07-01T09:00:00Z",
            "updated_at": "2026-07-01T09:00:00Z"
           },
           "created_at": "2026-07-13T12:00:00Z",
           "updated_at": "2026-07-13T12:00:00Z"
          }
         ],
         "customer": {
          "customer_id": "cust_xyz789",
          "email": "customer@example.com",
          "name": "Jane Doe",
          "phone_number": "+2348012345678",
          "metadata": {},
          "created_at": "2026-07-01T09:00:00Z",
          "updated_at": "2026-07-01T09:00:00Z"
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/subscriptions/cancel-subscription"
    }
   }
  },
  "/v1/refunds/by-charge/{payment_id}": {
   "get": {
    "tags": [
     "Refunds"
    ],
    "summary": "Retrieve a refund by charge",
    "description": "Retrieve the refund associated with a specific payment by `payment_id`.",
    "operationId": "getRefundByCharge",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "payment_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The ID of the payment whose refund you want to retrieve."
     }
    ],
    "responses": {
     "200": {
      "description": "Success - Refund retrieved for charge",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RefundResponse"
        },
        "example": {
         "refund_id": "3d0a86f5-1c47-4b92-8e6d-9f5b04c71a2e",
         "charge_id": "ch_2b7e5a9c1f04d63a8e5b1c9d7f602a34",
         "reference": "RF-20260712-0018",
         "status": "success",
         "requested_amount": "12.50",
         "refunded_amount": "12.50",
         "refund_fee_amount": "0.00",
         "fee_bearer": "customer",
         "reason": null,
         "created_at": "2026-07-12T09:14:05.100Z",
         "updated_at": "2026-07-12T09:19:37.640Z",
         "completed_at": "2026-07-12T09:19:37.640Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalServerError"
     }
    },
    "x-mint": {
     "href": "/api-reference/refunds/get-refund-by-charge"
    }
   }
  },
  "/v1/webhooks/endpoints": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Create a webhook endpoint",
    "description": "Register a URL to receive webhook events, and choose which events to subscribe to. The signing secret is returned once in the response. Requires the `webhooks:write` scope.",
    "operationId": "createWebhookEndpoint",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateWebhookEndpointRequest"
       },
       "example": {
        "name": "Production events",
        "url": "https://api.example.com/webhooks/bachs",
        "event_types": [
         "checkout.completed",
         "collection.succeeded",
         "payout.paid",
         "refund.paid"
        ],
        "event_source": "account"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "The created endpoint, including its signing secret.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CreateWebhookEndpointResponse"
        },
        "example": {
         "endpoint_id": "whe_a1e823c073ab743ce5969ceef2db4d42",
         "name": "Production events",
         "url": "https://api.example.com/webhooks/bachs",
         "enabled": true,
         "event_types": [
          "checkout.completed",
          "collection.succeeded",
          "payout.paid",
          "refund.paid"
         ],
         "event_source": "account",
         "created_at": "2026-03-09T10:00:00.000Z",
         "updated_at": "2026-03-09T10:00:00.000Z",
         "signing_secret": "whsec_62da9edb5b97b120f7d55e1e190118b0ec08fcace294dfaf211ec370b6d21f34"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   },
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "List webhook endpoints",
    "description": "List all webhook endpoints for your account. Requires the `webhooks:read` scope.",
    "operationId": "listWebhookEndpoints",
    "security": [],
    "responses": {
     "200": {
      "description": "Your webhook endpoints.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEndpointListResponse"
        },
        "example": [
         {
          "endpoint_id": "whe_a1e823c073ab743ce5969ceef2db4d42",
          "name": "Production events",
          "url": "https://api.example.com/webhooks/bachs",
          "enabled": true,
          "event_types": [
           "checkout.completed",
           "collection.succeeded",
           "payout.paid",
           "refund.paid"
          ],
          "event_source": "account",
          "created_at": "2026-03-09T10:00:00.000Z",
          "updated_at": "2026-03-09T10:00:00.000Z"
         },
         {
          "endpoint_id": "whe_e1eae19222ebc5e7e2b4270eaf6f4dec",
          "name": "Account monitor",
          "url": "https://api.example.com/webhooks/bachs/connected",
          "enabled": true,
          "event_types": [
           "account.updated",
           "capability.updated",
           "transfer.created"
          ],
          "event_source": "connect",
          "created_at": "2026-02-14T08:30:00.000Z",
          "updated_at": "2026-03-02T16:45:12.000Z"
         }
        ]
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    },
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      },
      "description": "Number of endpoints to return per page."
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of endpoints to skip before the page starts."
     },
     {
      "name": "cursor",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Cursor from a previous page's `pagination.next_cursor`. Takes precedence over `offset` when both are sent."
     }
    ]
   }
  },
  "/v1/webhooks/endpoints/{endpoint_id}": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Retrieve a webhook endpoint",
    "description": "Retrieve a single webhook endpoint by ID. Requires the `webhooks:read` scope.",
    "operationId": "getWebhookEndpoint",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     }
    ],
    "responses": {
     "200": {
      "description": "The endpoint.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEndpoint"
        },
        "example": {
         "endpoint_id": "whe_a1e823c073ab743ce5969ceef2db4d42",
         "name": "Production events",
         "url": "https://api.example.com/webhooks/bachs",
         "enabled": true,
         "event_types": [
          "checkout.completed",
          "collection.succeeded",
          "payout.paid",
          "refund.paid"
         ],
         "event_source": "account",
         "created_at": "2026-03-09T10:00:00.000Z",
         "updated_at": "2026-03-09T10:00:00.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   },
   "patch": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Update a webhook endpoint",
    "description": "Update an endpoint's name, URL, or subscribed events. Only the fields you send are changed. Requires the `webhooks:write` scope.",
    "operationId": "updateWebhookEndpoint",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/UpdateWebhookEndpointRequest"
       },
       "example": {
        "name": "Production events (v2 receiver)",
        "url": "https://api.example.com/webhooks/bachs/v2",
        "event_types": [
         "checkout.completed",
         "collection.succeeded",
         "collection.failed",
         "payout.paid",
         "refund.paid"
        ],
        "event_source": "all"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The updated endpoint.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEndpoint"
        },
        "example": {
         "endpoint_id": "whe_a1e823c073ab743ce5969ceef2db4d42",
         "name": "Production events (v2 receiver)",
         "url": "https://api.example.com/webhooks/bachs/v2",
         "enabled": true,
         "event_types": [
          "checkout.completed",
          "collection.succeeded",
          "collection.failed",
          "payout.paid",
          "refund.paid"
         ],
         "event_source": "all",
         "created_at": "2026-03-09T10:00:00.000Z",
         "updated_at": "2026-03-11T09:22:04.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   },
   "delete": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Delete a webhook endpoint",
    "description": "Delete a webhook endpoint. It stops receiving events immediately. Requires the `webhooks:write` scope.",
    "operationId": "deleteWebhookEndpoint",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     }
    ],
    "responses": {
     "200": {
      "description": "The endpoint was deleted.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DeleteWebhookEndpointResponse"
        },
        "example": {
         "status": "deleted",
         "endpoint_id": "whe_a1e823c073ab743ce5969ceef2db4d42"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/webhooks/endpoints/{endpoint_id}/secret": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Retrieve an endpoint's signing secret",
    "description": "Retrieve the current signing secret for an endpoint. Use it to verify the `X-Bachs-Signature` header on deliveries. Requires the `webhooks:read` scope.",
    "operationId": "getWebhookEndpointSecret",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     }
    ],
    "responses": {
     "200": {
      "description": "The endpoint and its signing secret.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEndpointSecretResponse"
        },
        "example": {
         "endpoint_id": "whe_a1e823c073ab743ce5969ceef2db4d42",
         "name": "Production events",
         "url": "https://api.example.com/webhooks/bachs",
         "enabled": true,
         "event_types": [
          "checkout.completed",
          "collection.succeeded",
          "payout.paid",
          "refund.paid"
         ],
         "event_source": "account",
         "created_at": "2026-03-09T10:00:00.000Z",
         "updated_at": "2026-03-09T10:00:00.000Z",
         "secret": "whsec_62da9edb5b97b120f7d55e1e190118b0ec08fcace294dfaf211ec370b6d21f34"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    },
    "x-excluded": true
   }
  },
  "/v1/webhooks/endpoints/{endpoint_id}/rotate-secret": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Rotate an endpoint's signing secret",
    "description": "Generate a new signing secret for an endpoint. The old secret stops working immediately, so update your verification before rotating. Requires the `webhooks:write` scope.",
    "operationId": "rotateWebhookEndpointSecret",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     }
    ],
    "responses": {
     "200": {
      "description": "The endpoint with its secret rotated.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEndpoint"
        },
        "example": {
         "endpoint_id": "whe_a1e823c073ab743ce5969ceef2db4d42",
         "name": "Production events",
         "url": "https://api.example.com/webhooks/bachs",
         "enabled": true,
         "event_types": [
          "checkout.completed",
          "collection.succeeded",
          "payout.paid",
          "refund.paid"
         ],
         "event_source": "account",
         "created_at": "2026-03-09T10:00:00.000Z",
         "updated_at": "2026-03-12T14:05:33.000Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/webhooks/endpoints/{endpoint_id}/metrics": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Retrieve endpoint delivery metrics",
    "description": "Retrieve delivery success and failure counts for an endpoint over a time range. Requires the `webhooks:read` scope.",
    "operationId": "getWebhookEndpointMetrics",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     },
     {
      "name": "period",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Grouping period, e.g. `day`."
     },
     {
      "name": "date_from",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "date-time"
      },
      "description": "Start of the range (ISO 8601)."
     },
     {
      "name": "date_to",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "date-time"
      },
      "description": "End of the range (ISO 8601)."
     }
    ],
    "responses": {
     "200": {
      "description": "Delivery metrics.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookMetricsResponse"
        },
        "example": {
         "total": "160",
         "period": "day",
         "data": [
          {
           "date": "2026-03-03",
           "success": 22,
           "failed": 0
          },
          {
           "date": "2026-03-04",
           "success": 19,
           "failed": 1
          },
          {
           "date": "2026-03-05",
           "success": 25,
           "failed": 0
          },
          {
           "date": "2026-03-06",
           "success": 18,
           "failed": 0
          },
          {
           "date": "2026-03-07",
           "success": 27,
           "failed": 2
          },
          {
           "date": "2026-03-08",
           "success": 21,
           "failed": 0
          },
          {
           "date": "2026-03-09",
           "success": 24,
           "failed": 1
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/webhooks/endpoints/{endpoint_id}/events": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "List events for an endpoint",
    "description": "List the events delivered (or attempted) to a specific endpoint. Requires the `webhooks:read` scope.",
    "operationId": "listWebhookEndpointEvents",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      },
      "description": "Maximum results to return (1\u2013100, default 50)."
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of results to skip."
     }
    ],
    "responses": {
     "200": {
      "description": "Events for the endpoint.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEndpointEventsListResponse"
        },
        "example": {
         "items": [
          {
           "event_id": "evt_5d50b401e3e47948235c374ae57b8807",
           "event_type": "customer.created",
           "entity_id": "cust_9ae63038729d2d6b793423bdbc27c19a",
           "attempts": 2,
           "success": 1,
           "failed": 1,
           "last_attempt_status": "succeeded",
           "last_attempt_http_status": 200,
           "last_attempt_error": null,
           "last_attempt_at": "2026-03-09T10:02:41.000Z"
          },
          {
           "event_id": "evt_2a960a1d977989742bbdceee5c7cc398",
           "event_type": "checkout.completed",
           "entity_id": "9d7c1f0b-4a52-4f0e-9d3b-6b8e2c11a4f7",
           "attempts": 1,
           "success": 0,
           "failed": 1,
           "last_attempt_status": "failed",
           "last_attempt_http_status": null,
           "last_attempt_error": "Connection timed out after 10s",
           "last_attempt_at": "2026-03-09T09:41:18.000Z"
          }
         ],
         "total": 2,
         "limit": 50,
         "offset": 0
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/webhooks/endpoints/{endpoint_id}/events/{event_id}": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Retrieve an endpoint event",
    "description": "Retrieve one event's full payload and delivery attempts for a specific endpoint. Requires the `webhooks:read` scope.",
    "operationId": "getWebhookEndpointEvent",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     },
     {
      "name": "event_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The event's ID.",
      "example": "evt_1a2b3c4d5e"
     }
    ],
    "responses": {
     "200": {
      "description": "The event with its payload and attempts.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEventDetail"
        },
        "example": {
         "event_id": "evt_5d50b401e3e47948235c374ae57b8807",
         "event_type": "customer.created",
         "entity_type": "customer",
         "entity_id": "cust_9ae63038729d2d6b793423bdbc27c19a",
         "created_at": "2026-03-09T10:00:00.000Z",
         "payload": {
          "id": "evt_5d50b401e3e47948235c374ae57b8807",
          "type": "customer.created",
          "created_at": "2026-03-09T10:00:00.000Z",
          "organization_id": "acct_MxIFSNnNbZ1N4jaP",
          "data": {
           "customer_id": "cust_9ae63038729d2d6b793423bdbc27c19a",
           "email": "ada@example.com",
           "name": "Ada Okafor",
           "phone_number": "+2348012345678",
           "metadata": {
            "signup_source": "web"
           },
           "billing_address": {
            "line1": "14 Marina Road",
            "line2": null,
            "city": "Lagos",
            "state": "Lagos",
            "postal_code": "101241",
            "country": "NG"
           },
           "created_at": "2026-03-09T10:00:00.000Z",
           "updated_at": "2026-03-09T10:00:00.000Z"
          }
         },
         "attempts": [
          {
           "attempt_id": "wha_8e42bc52310ceff8bed0ff7664efd4ed",
           "attempt_no": 2,
           "status": "succeeded",
           "callback_url": "https://api.example.com/webhooks/bachs",
           "http_status": 200,
           "response_snippet": "{\"received\":true}",
           "last_error": null,
           "created_at": "2026-03-09T10:02:41.000Z",
           "updated_at": "2026-03-09T10:02:41.000Z"
          },
          {
           "attempt_id": "wha_5566022efc62628d4098bb7ea1598837",
           "attempt_no": 1,
           "status": "failed",
           "callback_url": "https://api.example.com/webhooks/bachs",
           "http_status": 503,
           "response_snippet": "Service Unavailable",
           "last_error": "Endpoint returned HTTP 503",
           "created_at": "2026-03-09T10:00:02.000Z",
           "updated_at": "2026-03-09T10:00:12.000Z"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/webhooks/endpoints/{endpoint_id}/events/{event_id}/resend": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Resend an event to an endpoint",
    "description": "Re-deliver a past event to a specific endpoint. Requires the `webhooks:write` scope.",
    "operationId": "resendWebhookEvent",
    "security": [],
    "parameters": [
     {
      "name": "endpoint_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The webhook endpoint's ID.",
      "example": "whe_1a2b3c4d5e"
     },
     {
      "name": "event_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The event's ID.",
      "example": "evt_1a2b3c4d5e"
     }
    ],
    "responses": {
     "200": {
      "description": "The resend was queued.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ResendWebhookEventResponse"
        },
        "example": {
         "status": "queued",
         "attempt_id": "wha_8e42bc52310ceff8bed0ff7664efd4ed"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/webhooks/events": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "List webhook events",
    "description": "List all webhook events for your account, across every endpoint. Requires the `webhooks:read` scope.",
    "operationId": "listWebhookEvents",
    "security": [],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      },
      "description": "Maximum results to return (1\u2013100, default 50)."
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of results to skip."
     }
    ],
    "responses": {
     "200": {
      "description": "Your webhook events.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEventsListResponse"
        },
        "example": {
         "items": [
          {
           "event_id": "evt_5d50b401e3e47948235c374ae57b8807",
           "event_type": "customer.created",
           "entity_type": "customer",
           "entity_id": "cust_9ae63038729d2d6b793423bdbc27c19a",
           "created_at": "2026-03-09T10:00:00.000Z",
           "account": "acct_MxIFSNnNbZ1N4jaP",
           "attempts": 2,
           "success": 1,
           "failed": 1,
           "last_attempt_status": "succeeded",
           "last_attempt_http_status": 200,
           "last_attempt_error": null,
           "last_attempt_at": "2026-03-09T10:02:41.000Z"
          },
          {
           "event_id": "evt_2a960a1d977989742bbdceee5c7cc398",
           "event_type": "checkout.completed",
           "entity_type": "checkout",
           "entity_id": "9d7c1f0b-4a52-4f0e-9d3b-6b8e2c11a4f7",
           "created_at": "2026-03-09T09:41:07.000Z",
           "account": "acct_MxIFSNnNbZ1N4jaP",
           "attempts": 1,
           "success": 0,
           "failed": 1,
           "last_attempt_status": "failed",
           "last_attempt_http_status": null,
           "last_attempt_error": "Connection timed out after 10s",
           "last_attempt_at": "2026-03-09T09:41:18.000Z"
          }
         ],
         "total": 2,
         "limit": 50,
         "offset": 0
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/webhooks/events/{event_id}": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Retrieve a webhook event",
    "description": "Retrieve a single event's full payload and delivery attempts. Requires the `webhooks:read` scope.",
    "operationId": "getWebhookEvent",
    "security": [],
    "parameters": [
     {
      "name": "event_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The event's ID.",
      "example": "evt_1a2b3c4d5e"
     }
    ],
    "responses": {
     "200": {
      "description": "The event with its payload and attempts.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEventDetail"
        },
        "example": {
         "event_id": "evt_5d50b401e3e47948235c374ae57b8807",
         "event_type": "customer.created",
         "entity_type": "customer",
         "entity_id": "cust_9ae63038729d2d6b793423bdbc27c19a",
         "created_at": "2026-03-09T10:00:00.000Z",
         "payload": {
          "id": "evt_5d50b401e3e47948235c374ae57b8807",
          "type": "customer.created",
          "created_at": "2026-03-09T10:00:00.000Z",
          "organization_id": "acct_MxIFSNnNbZ1N4jaP",
          "data": {
           "customer_id": "cust_9ae63038729d2d6b793423bdbc27c19a",
           "email": "ada@example.com",
           "name": "Ada Okafor",
           "phone_number": "+2348012345678",
           "metadata": {
            "signup_source": "web"
           },
           "billing_address": {
            "line1": "14 Marina Road",
            "line2": null,
            "city": "Lagos",
            "state": "Lagos",
            "postal_code": "101241",
            "country": "NG"
           },
           "created_at": "2026-03-09T10:00:00.000Z",
           "updated_at": "2026-03-09T10:00:00.000Z"
          }
         },
         "attempts": [
          {
           "attempt_id": "wha_8e42bc52310ceff8bed0ff7664efd4ed",
           "attempt_no": 2,
           "status": "succeeded",
           "callback_url": "https://api.example.com/webhooks/bachs",
           "http_status": 200,
           "response_snippet": "{\"received\":true}",
           "last_error": null,
           "created_at": "2026-03-09T10:02:41.000Z",
           "updated_at": "2026-03-09T10:02:41.000Z"
          },
          {
           "attempt_id": "wha_5566022efc62628d4098bb7ea1598837",
           "attempt_no": 1,
           "status": "failed",
           "callback_url": "https://api.example.com/webhooks/bachs",
           "http_status": 503,
           "response_snippet": "Service Unavailable",
           "last_error": "Endpoint returned HTTP 503",
           "created_at": "2026-03-09T10:00:02.000Z",
           "updated_at": "2026-03-09T10:00:12.000Z"
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/transfers": {
   "post": {
    "tags": [
     "Transfers"
    ],
    "summary": "Create a transfer",
    "description": "Move funds between your platform balance and an account you own. This debits the source balance immediately and cannot be cancelled. Transfers draw on available balance only, move a single currency, and never take a balance below zero. See the [Split payments](/connect/split-payments) guide for the full flow.",
    "operationId": "createTransfer",
    "security": [
     {
      "ApiKeyAuth": [
       "transfers:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "X-Account-Id",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Act as this account, making it the debited side. Send it with `destination: \"self\"` to recover funds back to your platform.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateTransferRequest"
       },
       "example": {
        "destination": "acct_3Wq8ZfT1yHnJ5sVe",
        "amount": "7000.00",
        "currency": "NGN",
        "transfer_group": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
        "description": "Order #4471 seller share"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Transfer created and the balances updated.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TransferResponse"
        },
        "example": {
         "id": "tr_8c1e04a7b93f2d6540ab",
         "source": "acct_7KpQ2mNv4XbR9dLc",
         "destination": "acct_3Wq8ZfT1yHnJ5sVe",
         "amount": "7000.00",
         "currency": "NGN",
         "status": "paid",
         "description": "Order #4471 seller share",
         "metadata": {},
         "transfer_group": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
         "kind": "manual",
         "source_charge_id": null,
         "created_at": "2026-08-07T11:04:22.518Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   },
   "get": {
    "tags": [
     "Transfers"
    ],
    "summary": "List transfers",
    "description": "Returns transfers your platform was a party to, newest first.",
    "operationId": "listTransfers",
    "security": [
     {
      "ApiKeyAuth": [
       "transfers:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      },
      "description": "Number of transfers to return per page."
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of transfers to skip before the page starts."
     },
     {
      "name": "connected_account_id",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Return only transfers involving this account, in either direction.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     {
      "name": "kind",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "payout",
        "manual"
       ]
      },
      "description": "Filter to one class of movement: `payout` or `manual`. `platform_fee` is no longer accepted here, see [Platform fees](/connect/platform-fees).",
      "example": "payout"
     }
    ],
    "responses": {
     "200": {
      "description": "A page of transfers. Each entry in `items` is a [Transfer](/api-reference/transfers/get-transfer).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TransferListResponse"
        },
        "example": {
         "items": [
          {
           "id": "tr_8c1e04a7b93f2d6540ab",
           "source": "acct_7KpQ2mNv4XbR9dLc",
           "destination": "acct_3Wq8ZfT1yHnJ5sVe",
           "amount": "7000.00",
           "currency": "NGN",
           "status": "paid",
           "description": "Order #4471 seller share",
           "metadata": {},
           "transfer_group": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
           "kind": "payout",
           "source_charge_id": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
           "created_at": "2026-08-07T11:04:22.518Z"
          }
         ],
         "total": 128,
         "limit": 50,
         "offset": 0
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     }
    }
   }
  },
  "/v1/transfers/{transfer_id}": {
   "get": {
    "tags": [
     "Transfers"
    ],
    "summary": "Get a transfer",
    "description": "Retrieve a single transfer your platform was a party to. A transfer between two accounts you do not own returns `404` rather than `403`, so the response never confirms that an unrelated id exists.",
    "operationId": "getTransfer",
    "security": [
     {
      "ApiKeyAuth": [
       "transfers:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "transfer_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The transfer's ID.",
      "example": "tr_8c1e04a7b93f2d6540ab"
     }
    ],
    "responses": {
     "200": {
      "description": "The transfer.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TransferResponse"
        },
        "example": {
         "id": "tr_8c1e04a7b93f2d6540ab",
         "source": "acct_7KpQ2mNv4XbR9dLc",
         "destination": "acct_3Wq8ZfT1yHnJ5sVe",
         "amount": "7000.00",
         "currency": "NGN",
         "status": "paid",
         "description": "Order #4471 seller share",
         "metadata": {},
         "transfer_group": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
         "kind": "manual",
         "source_charge_id": null,
         "created_at": "2026-08-07T11:04:22.518Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/platform_fees": {
   "get": {
    "tags": [
     "Platform Fees"
    ],
    "summary": "List platform fees",
    "description": "Returns platform fees your organization was a party to, newest first. Both the account a fee was collected from and the platform that earned it can list it.",
    "operationId": "listPlatformFees",
    "security": [
     {
      "ApiKeyAuth": [
       "transfers:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      },
      "description": "Number of platform fees to return per page."
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      },
      "description": "Number of platform fees to skip before the page starts."
     },
     {
      "name": "charge",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Filter to the platform fee struck against this charge.",
      "example": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f"
     }
    ],
    "responses": {
     "200": {
      "description": "A page of platform fees. Each entry in `items` is a [Platform fee](/api-reference/platform-fees/get-platform-fee).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PlatformFeeListResponse"
        },
        "example": {
         "items": [
          {
           "id": "pf_8c1e04a7b93f2d6540ab1234",
           "charge": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
           "collected_from": "acct_3Wq8ZfT1yHnJ5sVe",
           "earned_by": "acct_7KpQ2mNv4XbR9dLc",
           "amount": "20000.00",
           "currency": "NGN",
           "amount_refunded": "0.00",
           "refunded": false,
           "created_at": "2026-08-07T11:04:22.518Z"
          }
         ],
         "pagination": {
          "next_cursor": null,
          "prev_cursor": null,
          "has_more": true,
          "limit": 50,
          "offset": 0,
          "returned": 1,
          "total": 42
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     }
    }
   }
  },
  "/v1/platform_fees/{fee_id}": {
   "get": {
    "tags": [
     "Platform Fees"
    ],
    "summary": "Get a platform fee",
    "description": "Retrieve a single platform fee your organization was a party to.",
    "operationId": "getPlatformFee",
    "security": [
     {
      "ApiKeyAuth": [
       "transfers:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "fee_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The platform fee's ID.",
      "example": "pf_8c1e04a7b93f2d6540ab1234"
     }
    ],
    "responses": {
     "200": {
      "description": "The platform fee.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PlatformFeeResponse"
        },
        "example": {
         "id": "pf_8c1e04a7b93f2d6540ab1234",
         "charge": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f",
         "collected_from": "acct_3Wq8ZfT1yHnJ5sVe",
         "earned_by": "acct_7KpQ2mNv4XbR9dLc",
         "amount": "20000.00",
         "currency": "NGN",
         "amount_refunded": "0.00",
         "refunded": false,
         "created_at": "2026-08-07T11:04:22.518Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/accounts/{account_id}/account-links": {
   "post": {
    "tags": [
     "Accounts"
    ],
    "summary": "Create an account link",
    "description": "Issue a hosted link that walks an account through its outstanding requirements. Creating a link invalidates any outstanding active link of the same `type` for that account, so create one at the moment you redirect rather than on every page render. Requires an active `connect` capability on your own platform. See [Onboarding](/connect/onboarding).",
    "operationId": "createAccountLink",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404` so the response never confirms that an unrelated account exists.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateAccountLinkRequest"
       },
       "example": {
        "type": "onboarding",
        "refresh_url": "https://adastores.example/connect/refresh",
        "return_url": "https://adastores.example/connect/return"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Account link created. `url` is returned only here and cannot be read back.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AccountLinkResponse"
        },
        "example": {
         "id": "alnk_3b7e12c9d4a05f68b1c2",
         "object": "connected_account_link",
         "account": "acct_3Wq8ZfT1yHnJ5sVe",
         "type": "onboarding",
         "created": "2026-08-07T11:04:22.518Z",
         "expires_at": "2026-09-06T11:04:22.518Z",
         "url": "https://connect.bachs.io/setup/c/acct_3Wq8ZfT1yHnJ5sVe/al_kQ2v8nS1xJd0pR7mLtY4wZ6aHb3cFg9e",
         "previous_link_superseded": false
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/accounts/{account_id}/capabilities": {
   "get": {
    "tags": [
     "Accounts"
    ],
    "summary": "List capabilities",
    "description": "List every capability applicable to an account, including ones it has never requested. A capability with no record reports `unrequested` rather than being omitted, so you can tell \"never asked for\" apart from \"turned off\". See [Capabilities](/connect/capabilities).",
    "operationId": "listCapabilities",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404` so the response never confirms that an unrelated account exists.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     }
    ],
    "responses": {
     "200": {
      "description": "The account's capabilities.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ConnectedAccountCapabilitiesResponse"
        },
        "example": {
         "items": [
          {
           "name": "payouts",
           "status": "active",
           "requested": true,
           "status_details": null
          },
          {
           "name": "transfers",
           "status": "restricted",
           "requested": true,
           "status_details": [
            {
             "code": "platform_disabled",
             "resolution": "Contact support to re-enable this capability.",
             "message": "This capability was disabled by the platform."
            }
           ]
          },
          {
           "name": "conversions",
           "status": "unrequested",
           "requested": false,
           "status_details": null
          },
          {
           "name": "connect",
           "status": "unrequested",
           "requested": false,
           "status_details": null
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/accounts/{account_id}/documents": {
   "post": {
    "tags": [
     "Connected Accounts"
    ],
    "summary": "Attach a company document",
    "description": "Point one of the company's document slots at an already-uploaded file. Upload the file first with `POST /v1/utilities/uploads`, then reference its `upload_id` here as `file`. `document` names the company slot the file satisfies (for example a certificate of incorporation or a memorandum), and which slots exist depends on the company's structure and country. This attaches company-level paperwork; a person's ID document attaches to the person instead. See [Requirements](/connect/requirements).",
    "operationId": "attachCompanyDocument",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "example": {
        "file": "upl_7c2f9a10bd4e",
        "document": "certificate_of_incorporation"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "The document attached to the company.",
      "content": {
       "application/json": {
        "example": {
         "id": "doc_9b21ec70f5aa",
         "document_type": "certificate_of_incorporation",
         "file_name": "cac-certificate.pdf",
         "uploaded_at": "2026-08-07T09:24:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/reference/banks": {
   "get": {
    "tags": [
     "Reference"
    ],
    "summary": "List banks",
    "description": "The banks an account can name as a payout destination. Use the `code` from this list when you resolve an account number or submit `payout_destination`.",
    "operationId": "listReferenceBanks",
    "security": [
     {
      "BearerAuth": []
     },
     {
      "ApiKeyAuth": []
     },
     {
      "ConnectSessionAuth": []
     }
    ],
    "parameters": [
     {
      "name": "country",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Two-letter ISO 3166-1 country. Falls back to your own platform's country, and fails with `400` when neither is set.",
      "example": "NG"
     }
    ],
    "responses": {
     "200": {
      "description": "Banks available in the resolved country.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TaskBankListResponse"
        },
        "example": {
         "country": "NG",
         "banks": [
          {
           "name": "Providus Bank",
           "code": "101"
          },
          {
           "name": "Sterling Bank",
           "code": "232"
          }
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/reference/momo": {
   "get": {
    "tags": [
     "Reference"
    ],
    "summary": "List mobile money providers",
    "description": "The mobile money operators an account can name as a payout destination.",
    "operationId": "listReferenceMomoProviders",
    "security": [
     {
      "BearerAuth": []
     },
     {
      "ApiKeyAuth": []
     },
     {
      "ConnectSessionAuth": []
     }
    ],
    "parameters": [
     {
      "name": "country",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Two-letter ISO 3166-1 country. Falls back to your own platform's country, and fails with `400` when neither is set.",
      "example": "GH"
     }
    ],
    "responses": {
     "200": {
      "description": "Mobile money providers available in the resolved country.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/TaskMobileMoneyListResponse"
        },
        "example": {
         "country": "GH",
         "providers": [
          "MTN",
          "Vodafone",
          "AirtelTigo"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/reference/business-structures": {
   "get": {
    "tags": [
     "Reference"
    ],
    "summary": "List business structures",
    "description": "The legal structures a registered business can declare as `company.structure`, for the resolved country. Each carries a `value` to submit, a display `label`, and a `description`. Which documents a structure owes depends on it. See [Requirements](/connect/requirements).",
    "operationId": "listReferenceBusinessStructures",
    "security": [
     {
      "BearerAuth": []
     },
     {
      "ApiKeyAuth": []
     },
     {
      "ConnectSessionAuth": []
     }
    ],
    "parameters": [
     {
      "name": "country",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Two-letter ISO 3166-1 country. Falls back to your own platform's country.",
      "example": "NG"
     }
    ],
    "responses": {
     "200": {
      "description": "Business structures available in the resolved country.",
      "content": {
       "application/json": {
        "example": {
         "country": "NG",
         "structures": [
          {
           "value": "business_name",
           "label": "Business Name (BN)",
           "description": "A sole trader or partnership registered with the CAC. No shareholders."
          },
          {
           "value": "private_incorporated",
           "label": "Private Company (RC / LTD)",
           "description": "A company limited by shares, with directors and shareholders."
          },
          {
           "value": "incorporated_trustees",
           "label": "Incorporated Trustees (IT)",
           "description": "An NGO, church, association or foundation registered as trustees."
          }
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    }
   }
  },
  "/v1/reference/product-categories": {
   "get": {
    "tags": [
     "Reference"
    ],
    "summary": "List product categories",
    "description": "The industry categories a business can declare as `business_profile.product_category`. Returns a flat `categories` list of `{value, label}` and the same values grouped into `sections` for display. Submit the `value`. See [Requirements](/connect/requirements).",
    "operationId": "listReferenceProductCategories",
    "security": [
     {
      "BearerAuth": []
     },
     {
      "ApiKeyAuth": []
     },
     {
      "ConnectSessionAuth": []
     }
    ],
    "responses": {
     "200": {
      "description": "The product categories and their display sections.",
      "content": {
       "application/json": {
        "example": {
         "categories": [
          {
           "value": "software_as_a_service_saas",
           "label": "Software as a service (SaaS)"
          },
          {
           "value": "mobile_or_web_app",
           "label": "Mobile or web app"
          }
         ],
         "sections": [
          {
           "label": "Software & technology",
           "categories": [
            "software_as_a_service_saas",
            "mobile_or_web_app"
           ]
          }
         ]
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    }
   }
  },
  "/v1/accounts/{account_id}/persons": {
   "get": {
    "tags": [
     "Persons"
    ],
    "summary": "List persons",
    "description": "The people behind the account: its representative, beneficial owners and directors.",
    "operationId": "listConnectedAccountPersons",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404`.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 50
      }
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 0,
       "default": 0
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The account's persons.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PersonListResponse"
        },
        "example": {
         "items": [
          {
           "id": "per_3a91c0d7",
           "first_name": "Ada",
           "last_name": "Obi",
           "dob": "1990-04-12",
           "address": {
            "line1": "14 Balogun Street",
            "city": "Lagos",
            "state": "Lagos",
            "postal_code": "101241",
            "country": "NG"
           },
           "phone": "+2348012345678",
           "email": "ada@example.com",
           "id_number_provided": true,
           "relationship": {
            "representative": true,
            "owner": true,
            "director": false,
            "executive": false,
            "percent_ownership": 60,
            "title": "Founder"
           },
           "verification": {
            "status": "verified",
            "document_provided": true,
            "failure_reason": null
           },
           "created_at": "2026-08-10T09:31:12.000Z",
           "updated_at": "2026-08-11T14:05:40.219Z"
          },
          {
           "id": "per_9c40be12",
           "first_name": "Tunde",
           "last_name": "Bello",
           "dob": "1986-11-02",
           "address": null,
           "phone": null,
           "email": null,
           "id_number_provided": false,
           "relationship": {
            "representative": false,
            "owner": false,
            "director": true,
            "executive": false,
            "percent_ownership": null,
            "title": "Non-executive director"
           },
           "verification": {
            "status": "unverified",
            "document_provided": false,
            "failure_reason": null
           },
           "created_at": "2026-08-10T09:44:07.000Z",
           "updated_at": "2026-08-10T09:44:07.000Z"
          }
         ],
         "total": 2,
         "limit": 50,
         "offset": 0
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   },
   "post": {
    "tags": [
     "Persons"
    ],
    "summary": "Add a person",
    "description": "Add a person to the account. Roles are flags, so one person can be representative, owner and director at once.",
    "operationId": "createConnectedAccountPerson",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404`.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/PersonWriteRequest"
       },
       "example": {
        "first_name": "Ada",
        "last_name": "Obi",
        "dob": "1990-04-12",
        "address": {
         "line1": "14 Balogun Street",
         "city": "Lagos",
         "state": "Lagos",
         "postal_code": "101241",
         "country": "NG"
        },
        "phone": "+2348012345678",
        "email": "ada@example.com",
        "id_number": "22345678901",
        "relationship": {
         "representative": true,
         "owner": true,
         "director": false,
         "executive": false,
         "percent_ownership": 60,
         "title": "Founder"
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "The person that was added.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PersonResponse"
        },
        "example": {
         "id": "per_3a91c0d7",
         "first_name": "Ada",
         "last_name": "Obi",
         "dob": "1990-04-12",
         "address": {
          "line1": "14 Balogun Street",
          "city": "Lagos",
          "state": "Lagos",
          "postal_code": "101241",
          "country": "NG"
         },
         "phone": "+2348012345678",
         "email": "ada@example.com",
         "id_number_provided": true,
         "relationship": {
          "representative": true,
          "owner": true,
          "director": false,
          "executive": false,
          "percent_ownership": 60,
          "title": "Founder"
         },
         "verification": {
          "status": "unverified",
          "document_provided": false,
          "failure_reason": null
         },
         "created_at": "2026-08-10T09:31:12.000Z",
         "updated_at": "2026-08-10T09:31:12.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/accounts/{account_id}/persons/{person_id}": {
   "get": {
    "tags": [
     "Persons"
    ],
    "summary": "Read a person",
    "description": "Read one person. Requirement keys are anchored to the person id, so `persons.per_3a91c0d7.id_document` names exactly who this is about.",
    "operationId": "getConnectedAccountPerson",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:read"
      ]
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404`.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     {
      "name": "person_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The person on that account.",
      "example": "per_3a91c0d7"
     }
    ],
    "responses": {
     "200": {
      "description": "The person.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PersonResponse"
        },
        "example": {
         "id": "per_3a91c0d7",
         "first_name": "Ada",
         "last_name": "Obi",
         "dob": "1990-04-12",
         "address": {
          "line1": "14 Balogun Street",
          "city": "Lagos",
          "state": "Lagos",
          "postal_code": "101241",
          "country": "NG"
         },
         "phone": "+2348012345678",
         "email": "ada@example.com",
         "id_number_provided": true,
         "relationship": {
          "representative": true,
          "owner": true,
          "director": false,
          "executive": false,
          "percent_ownership": 60,
          "title": "Founder"
         },
         "verification": {
          "status": "verified",
          "document_provided": true,
          "failure_reason": null
         },
         "created_at": "2026-08-10T09:31:12.000Z",
         "updated_at": "2026-08-11T14:05:40.219Z"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   },
   "post": {
    "tags": [
     "Persons"
    ],
    "summary": "Update a person",
    "description": "Edit one person in place. Keys you omit are left alone; sending a key as `null` clears it.",
    "operationId": "updateConnectedAccountPerson",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404`.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     {
      "name": "person_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The person on that account.",
      "example": "per_3a91c0d7"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/PersonWriteRequest"
       },
       "example": {
        "last_name": "Obi-Nwosu",
        "phone": null,
        "relationship": {
         "director": true
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The updated person.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PersonResponse"
        },
        "example": {
         "id": "per_3a91c0d7",
         "first_name": "Ada",
         "last_name": "Obi-Nwosu",
         "dob": "1990-04-12",
         "address": {
          "line1": "14 Balogun Street",
          "city": "Lagos",
          "state": "Lagos",
          "postal_code": "101241",
          "country": "NG"
         },
         "phone": null,
         "email": "ada@example.com",
         "id_number_provided": true,
         "relationship": {
          "representative": true,
          "owner": true,
          "director": true,
          "executive": false,
          "percent_ownership": 60,
          "title": "Founder"
         },
         "verification": {
          "status": "verified",
          "document_provided": true,
          "failure_reason": null
         },
         "created_at": "2026-08-10T09:31:12.000Z",
         "updated_at": "2026-08-11T16:22:03.884Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "422": {
      "$ref": "#/components/responses/ValidationError"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   },
   "delete": {
    "tags": [
     "Persons"
    ],
    "summary": "Remove a person",
    "description": "Remove a person, along with the requirements that were only about them. The representative cannot be removed, since nothing would ask for a replacement, and returns `400 representative_cannot_be_removed`.",
    "operationId": "deleteConnectedAccountPerson",
    "security": [
     {
      "ApiKeyAuth": [
       "connected_accounts:write"
      ]
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The account to act on. It must be one of your own accounts; any other ID returns `404`.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     {
      "name": "person_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The person on that account.",
      "example": "per_3a91c0d7"
     }
    ],
    "responses": {
     "204": {
      "description": "The person was removed."
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     }
    }
   }
  },
  "/v1/accounts/{account_id}/persons/{person_id}/documents": {
   "post": {
    "tags": [
     "Persons"
    ],
    "summary": "Attach a document to a person",
    "description": "Point one of a person's document slots at an already-uploaded file. Upload the file first with `POST /v1/utilities/uploads`, then reference its `upload_id` here as `file`. `document` is `primary_verification` (government ID) or `secondary_verification` (address evidence); a two-sided card is two attachments, each with its own `side`. Attaching does not verify: a reviewer accepting the document is what moves the person's `verification.status` to `passed`. See [Verify an account's identity](/connect/guides/identity-verification).",
    "operationId": "attachPersonDocument",
    "security": [
     {
      "ApiKeyAuth": []
     }
    ],
    "parameters": [
     {
      "name": "account_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "person_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "example": {
        "file": "upl_7c2f9a10bd4e",
        "document": "primary_verification",
        "side": "front"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "The document attached to the person.",
      "content": {
       "application/json": {
        "example": {
         "id": "doc_5f0339fac1ae",
         "person": "per_3a91c0d7f6e2b8149a05",
         "document_type": "primary_verification",
         "file_name": "ada-nin.jpg",
         "uploaded_at": "2026-08-07T09:23:00.000Z"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  },
  "/v1/misc/bank-accounts/resolve": {
   "post": {
    "tags": [
     "Misc"
    ],
    "summary": "Resolve a bank account",
    "description": "Resolve an account number and bank code to the account holder's name. Worth calling before you submit a payout destination: it turns a rejection days later into an inline error while the account holder is still on the page.",
    "operationId": "resolveReferenceBankAccount",
    "security": [
     {
      "BearerAuth": []
     },
     {
      "ApiKeyAuth": []
     },
     {
      "ConnectSessionAuth": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/ResolveTaskBankAccountRequest"
       },
       "example": {
        "account_number": "0123456789",
        "bank_code": "101",
        "country": "NG"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The lookup result. Check `resolved` before you trust `account_name`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ResolveTaskBankAccountResponse"
        },
        "example": {
         "resolved": true,
         "account_name": "ADA OKAFOR",
         "account_number": "0123456789",
         "message": null
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "ApiKeyAuth": {
    "type": "http",
    "scheme": "bearer",
    "bearerFormat": "API Key",
    "description": "Bearer token authentication. Pass your API key as `Authorization: Bearer sk_...`. See [Authentication](/authentication) for keys, scopes, and sandbox vs production."
   }
  },
  "schemas": {
   "MerchantIntent": {
    "type": "object",
    "required": [
     "currency"
    ],
    "properties": {
     "currency": {
      "type": "string",
      "description": "Base currency code (e.g., 'USD', 'NGN'). Must be a supported fiat currency.",
      "example": "USD"
     },
     "amount": {
      "type": "string",
      "description": "Base amount as decimal string. Required for a fixed price; omit for a custom (buyer-entered) or free price. Minimum 100 for `NGN`, 1 for `USD` (and per-currency minimums for other supported currencies).",
      "example": "50.00"
     },
     "price_type": {
      "type": "string",
      "enum": [
       "fixed",
       "custom",
       "free"
      ],
      "description": "`fixed` (default when amount is set) | `custom` (buyer enters the amount at checkout, within optional bounds, via the checkout-level set-amount) | `free` ($0)."
     },
     "preset_amount": {
      "type": "string",
      "description": "Suggested starting amount for a custom price.",
      "example": "10.00"
     },
     "minimum_amount": {
      "type": "string",
      "description": "Lower bound for a custom price.",
      "example": "5.00"
     },
     "maximum_amount": {
      "type": "string",
      "description": "Upper bound for a custom price.",
      "example": "100.00"
     },
     "currency_options": {
      "type": "object",
      "description": "Currency-specific pricing overrides. Keys are fiat currency codes, values are decimal amount strings.",
      "additionalProperties": {
       "type": "string"
      },
      "example": {
       "NGN": "75000.00",
       "GHS": "620.00"
      }
     }
    }
   },
   "ProductItemRequest": {
    "type": "object",
    "required": [
     "product_id"
    ],
    "properties": {
     "product_id": {
      "type": "string",
      "description": "Product ID to include in checkout.",
      "example": "prod_abc123"
     },
     "quantity": {
      "type": "integer",
      "minimum": 1,
      "default": 1,
      "description": "Number of units for the product item.",
      "example": 1
     },
     "amount": {
      "type": "string",
      "nullable": true,
      "description": "Chosen amount for a pay-what-you-want price. For a catalog CUSTOM product, or an ad-hoc CUSTOM price (pre-filling the buyer's amount).",
      "example": "29.00"
     },
     "pricing": {
      "nullable": true,
      "$ref": "#/components/schemas/AdhocPriceInput"
     }
    }
   },
   "AdhocPriceInput": {
    "type": "object",
    "description": "Ad-hoc price override for this checkout only (no product is created). Priced in the product's primary currency. Supports the same price types as catalog prices: `fixed`, `custom`, `free`.",
    "properties": {
     "price_type": {
      "type": "string",
      "enum": [
       "fixed",
       "custom",
       "free"
      ],
      "default": "fixed",
      "description": "`fixed` sets a set amount via `amount`. `custom` is pay-what-you-want, bounded by `minimum_amount`/`maximum_amount` with an optional `preset_amount`; the buyer picks the amount at checkout. `free` is a $0 line that completes without payment; on a recurring product it creates a free subscription (no card, renews with no charge)."
     },
     "amount": {
      "type": "string",
      "nullable": true,
      "description": "The price, for a `fixed` ad-hoc price. Required for `fixed`; not valid for `custom`.",
      "example": "19.00"
     },
     "preset_amount": {
      "type": "string",
      "nullable": true,
      "description": "Suggested starting amount for a `custom` ad-hoc price.",
      "example": "10.00"
     },
     "minimum_amount": {
      "type": "string",
      "nullable": true,
      "description": "Lower bound for a `custom` ad-hoc price.",
      "example": "5.00"
     },
     "maximum_amount": {
      "type": "string",
      "nullable": true,
      "description": "Upper bound for a `custom` ad-hoc price.",
      "example": "100.00"
     }
    }
   },
   "ExistingCustomerRequest": {
    "type": "object",
    "required": [
     "customer_id"
    ],
    "properties": {
     "customer_id": {
      "type": "string",
      "description": "Existing customer ID.",
      "example": "cust_1a2b3c4d5e6f"
     }
    }
   },
   "NewCustomerRequest": {
    "type": "object",
    "required": [
     "email",
     "name"
    ],
    "properties": {
     "email": {
      "type": "string",
      "format": "email",
      "description": "Customer email address.",
      "example": "jane@example.com"
     },
     "name": {
      "type": "string",
      "description": "Customer full name.",
      "example": "Jane Doe"
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "description": "Customer phone number.",
      "example": "+2348012345678"
     }
    }
   },
   "CreateCheckoutSessionRequest": {
    "type": "object",
    "oneOf": [
     {
      "required": [
       "product_cart"
      ],
      "description": "Checkout with a cart of catalog products (each item may override its price via `pricing`)."
     },
     {
      "required": [
       "pricing"
      ],
      "description": "Pure checkout with a raw amount and currency, no products."
     }
    ],
    "properties": {
     "billing_currency": {
      "type": "string",
      "nullable": true,
      "description": "Optional checkout billing currency. If omitted, defaults to product pricing currency.",
      "example": "USD"
     },
     "payment_method_types": {
      "type": "array",
      "nullable": true,
      "description": "Restricts the checkout to specific payment methods. Values are exact payment-method corridors, not payment types: `USD_CARD` and `NGN_CARD` are separate corridors, as is each of the nine mobile money corridors. Valid values: `USD_CARD` (US card, USD), `NGN_CARD` (Nigerian card, NGN), `NGN_BANK_TRANSFER` (Nigerian bank transfer, NGN), `MOMO_GHS` (Ghana mobile money), `MOMO_KES` (Kenya mobile money), `MOMO_TZS` (Tanzania mobile money), `MOMO_UGX` (Uganda mobile money), `MOMO_XAF` (Central Africa CFA mobile money), `MOMO_XOF` (West Africa CFA mobile money), `MOMO_RWF` (Rwanda mobile money), `MOMO_MWK` (Malawi mobile money), `MOMO_ZMW` (Zambia mobile money), and `CRYPTO` (all supported crypto assets). A corridor you leave out is not offered. Restricting only narrows what the customer sees: it never adds a corridor your account is not already enabled for. If the restriction leaves no payable method, the request is rejected.",
      "items": {
       "type": "string"
      },
      "example": [
       "USD_CARD",
       "NGN_BANK_TRANSFER"
      ]
     },
     "cancel_url": {
      "type": "string",
      "format": "uri",
      "nullable": true,
      "description": "Where to send the customer if they cancel or abandon the checkout. Returned on the checkout so the hosted page can route back to it.",
      "example": "https://shop.example.com/cart"
     },
     "return_url": {
      "type": "string",
      "format": "uri",
      "nullable": true,
      "description": "Deprecated alias for `success_url`, kept for backward compatibility. If both are set, `success_url` wins.",
      "example": "https://shop.example.com/thanks"
     },
     "success_url": {
      "type": "string",
      "description": "Where to redirect the customer after a successful payment. Bachs appends `?checkout_id=<id>`. This is the primary success-redirect field.",
      "example": "https://shop.example.com/success"
     },
     "customer": {
      "nullable": true,
      "oneOf": [
       {
        "$ref": "#/components/schemas/ExistingCustomerRequest"
       },
       {
        "$ref": "#/components/schemas/NewCustomerRequest"
       }
      ],
      "description": "Customer for the checkout session, optional. Omit it and the hosted checkout page collects the buyer's email and name instead, recording them on `customer_details`. Send `customer_creation: always` to also create a customer record from what they give. Required for a subscription checkout, which has no later opportunity to collect it."
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "description": "Optional metadata (max 20 keys, max 10KB total).",
      "additionalProperties": true
     },
     "product_cart": {
      "type": "array",
      "minItems": 1,
      "maxItems": 20,
      "items": {
       "$ref": "#/components/schemas/ProductItemRequest"
      },
      "description": "Catalog products to include in this checkout session. Mutually exclusive with `pricing`."
     },
     "pricing": {
      "nullable": true,
      "description": "Raw pricing for a product-less (pure) checkout. Mutually exclusive with `product_cart`.",
      "$ref": "#/components/schemas/MerchantIntent"
     },
     "platform_fee": {
      "type": "string",
      "nullable": true,
      "description": "The platform's cut of this sale, in the base currency of the sale, taken from the merchant's proceeds rather than from Bachs's processing fee. On a destination charge, this is one of two ways to state the split: the account receives the gross minus this amount. Mutually exclusive with `transfer_data.amount`. A destination charge needs one of the two; a direct charge can set this alone to move part of its own charge up to the platform. See [Platform fees](/connect/platform-fees).",
      "example": "20000.00"
     },
     "transfer_data": {
      "nullable": true,
      "description": "Names the account this checkout pays out to. Its presence, on its own, is what makes this a destination charge belonging to your platform rather than the account. A destination charge needs a split term: either `platform_fee` on the request root, or `transfer_data.amount` here. Omit `transfer_data` entirely, and act as the account with `X-Account-Id` instead, for a direct charge. See [Destination charges](/connect/split-payments/destination).",
      "$ref": "#/components/schemas/TransferDataInput"
     },
     "reference": {
      "type": "string",
      "maxLength": 128,
      "nullable": true,
      "description": "Your own reference for this session, unique per account. Omit it and the session has none; use the session's `id` to track it.",
      "example": "order_9876"
     },
     "expires_in_minutes": {
      "type": "integer",
      "minimum": 1,
      "maximum": 1440,
      "default": 60,
      "description": "Minutes until the checkout session expires. Defaults to 60. After expiry the checkout URL is invalid.",
      "example": 60
     },
     "customer_creation": {
      "type": "string",
      "enum": [
       "always",
       "if_required"
      ],
      "default": "if_required",
      "description": "Whether a buyer who identifies themselves on the hosted page also becomes a customer record. Applies only when you omit `customer`. `if_required` (default) keeps them out of your directory: `customer` stays `null`, no `customer.created` or `customer.updated` webhook fires, and their email and name reach you on `customer_details` instead. Their purchases still group together in your dashboard. `always` adds them to your directory, matched by email to a customer you already hold where one exists, and returns it on `customer`. That match is on the email alone, and an email typed on the checkout page is not verified, so a buyer who knows one of your customers' addresses has their purchase recorded against that customer. Ignored for a subscription or `setup` checkout, which always create a customer. See [Whether a guest becomes a customer](/guides/checkout/checkout-sessions#whether-a-guest-becomes-a-customer-customer-creation).",
      "example": "if_required"
     },
     "save_payment_method": {
      "type": "boolean",
      "default": false,
      "description": "Save the customer's card so you can charge it later without them present. Send it with a price and the customer pays now and the card is kept. Send it with no pricing and the checkout collects a card and charges nothing, which needs an existing customer (`customer.customer_id`) for the card to belong to. Only cards can be charged again, so a checkout that offers none is refused with `CHECKOUT_CANNOT_SAVE_PAYMENT_METHOD`. Saving cards is in beta and this might change."
     }
    }
   },
   "TransferDataInput": {
    "type": "object",
    "required": [
     "destination"
    ],
    "properties": {
     "destination": {
      "type": "string",
      "description": "The account to transfer the sale to. Its presence, on its own, is what makes this a destination charge. It must be one of your own accounts; any other ID returns `404` so the response never confirms that an unrelated account exists.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     "amount": {
      "type": "string",
      "nullable": true,
      "description": "What the destination account receives, in the base currency of the sale. Supply this instead of `platform_fee` to fix the seller's share and let the platform absorb any variance in the total. Mutually exclusive with `platform_fee`; a request setting both is rejected with `400`.",
      "example": "80000.00"
     }
    }
   },
   "CreateRefundRequest": {
    "type": "object",
    "required": [
     "charge_id",
     "reference"
    ],
    "properties": {
     "charge_id": {
      "type": "string",
      "description": "The ID of the payment to refund.",
      "example": "ch_1a2b3c4d5e6f"
     },
     "reference": {
      "type": "string",
      "maxLength": 128,
      "description": "Your unique identifier for this refund. Must be unique per account and environment.",
      "example": "refund_9876"
     },
     "refund_address": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "Destination wallet address for crypto refunds. Required when the charge currency is a cryptocurrency.",
      "example": "0xabc123def456"
     },
     "amount": {
      "type": "string",
      "nullable": true,
      "description": "Optional partial refund amount in the charge settlement currency. Omit to refund the full remaining refundable balance.",
      "example": "10.00"
     },
     "fee_bearer": {
      "type": "string",
      "nullable": true,
      "enum": [
       "org",
       "customer"
      ],
      "description": "Who absorbs the refund fee. `org`: the fee is charged to your balance on top of the amount returned. `customer`: the fee is taken out of what the customer receives. Defaults to the fee handling set on your account. Case is ignored.",
      "example": "org"
     },
     "reason": {
      "type": "string",
      "nullable": true,
      "maxLength": 500,
      "description": "Human-readable reason for the refund.",
      "example": "Customer requested cancellation"
     },
     "idempotency_key": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "A key you supply to make this request idempotent. If you send the same idempotency_key twice for the same charge, the second request returns the existing refund.",
      "example": "idem_9f8e7d6c5b"
     },
     "simulated_outcome": {
      "type": "string",
      "nullable": true,
      "enum": [
       "success",
       "failed"
      ],
      "description": "Test mode only. Force a specific refund outcome. Omit to use the default sandbox outcome.",
      "example": "success"
     }
    }
   },
   "RefundResponse": {
    "type": "object",
    "properties": {
     "refund_id": {
      "type": "string",
      "description": "Pass this to retrieve the refund later.",
      "example": "rfnd_4b9c2e7a1d35a0f81c62"
     },
     "charge_id": {
      "type": "string",
      "description": "The charge whose funds are being returned. A charge carries at most one refund that did not fail, so this value appears on one refund at a time.",
      "example": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f"
     },
     "reference": {
      "type": "string",
      "description": "The reference you supplied on creation.",
      "example": "refund_9876"
     },
     "status": {
      "type": "string",
      "enum": [
       "processing",
       "success",
       "failed"
      ],
      "description": "Where the refund has reached. `processing`: the return has been accepted and your balance is already reserved, but the outcome is not yet known. `success`: the funds have reached the customer; this is final and cannot be reversed. `failed`: the return did not go through and the reserved balance has been released. This is final for this refund, but it moved no money, so the payment becomes refundable again and you can create a new refund for it.",
      "example": "processing"
     },
     "requested_amount": {
      "type": "string",
      "description": "The refund amount you requested, in the charge's settlement currency.",
      "example": "29.00"
     },
     "refunded_amount": {
      "type": "string",
      "nullable": true,
      "description": "The amount actually returned to the customer. Null until the refund completes or partially settles.",
      "example": null
     },
     "refund_fee_amount": {
      "type": "string",
      "description": "Fee charged for this refund, in the charge's settlement currency. \"0\" if no fee applies.",
      "example": "0.00"
     },
     "fee_bearer": {
      "type": "string",
      "enum": [
       "org",
       "customer"
      ],
      "description": "Who absorbs the refund fee. `org`: the fee is charged to your balance on top of the amount returned. `customer`: the fee is taken out of what the customer receives.",
      "example": "org"
     },
     "reason": {
      "type": "string",
      "nullable": true,
      "description": "The reason you provided, or null if none was given.",
      "example": "Customer requested cancellation"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp when the refund was created.",
      "example": "2026-04-27T12:00:00Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp of the last status update.",
      "example": "2026-04-27T12:00:00Z"
     },
     "completed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when the refund reached a terminal status (`success` or `failed`). Null while still processing.",
      "example": null
     }
    }
   },
   "RefundListResponse": {
    "type": "object",
    "properties": {
     "total": {
      "type": "integer",
      "description": "Total number of refunds matching the query, across all pages.",
      "example": 42
     },
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/RefundResponse"
      },
      "description": "Refund objects for the current page."
     }
    }
   },
   "CreateCheckoutSessionResponse": {
    "type": "object",
    "description": "Response containing checkout session details and hosted checkout URL.",
    "properties": {
     "checkout_id": {
      "type": "string",
      "description": "Unique identifier for the underlying checkout.",
      "example": "5d7ab015-5886-4a1e-89bb-abe499d0b8ee"
     },
     "checkout_url": {
      "type": "string",
      "format": "uri",
      "description": "Hosted checkout URL where your customer can complete payment.",
      "example": "https://checkout.bachs.io/c/Mz9wDp3sVn7QaTf"
     },
     "status": {
      "type": "string",
      "enum": [
       "open",
       "completed",
       "expired",
       "cancelled"
      ],
      "description": "Current checkout status. `open`: awaiting customer payment, where every new session starts. `completed`: payment succeeded, a terminal state. `expired`: the session window elapsed before payment, a terminal state. `cancelled`: cancelled before completion, a terminal state.",
      "example": "open"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp indicating when the checkout will expire. After this time, customers cannot complete payment through this checkout.",
      "example": "2026-01-24T15:30:00.000Z"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp indicating when the checkout was created.",
      "example": "2026-01-24T14:30:00.000Z"
     },
     "reference": {
      "type": "string",
      "nullable": true,
      "description": "Your own reference for this checkout, echoed back unchanged. `null` when you did not supply one.",
      "example": "order_9876"
     },
     "platform_fee": {
      "type": "string",
      "nullable": true,
      "description": "The platform's cut of this sale, echoed back from the request, in the base currency of the sale. The key is always present; it reads `null`, not `\"0.00\"`, on a checkout that carries no fee, and on a checkout that split the sale with `transfer_data.amount` instead. See [Platform fees](/connect/platform-fees).",
      "example": "20000.00"
     },
     "destination_amount": {
      "type": "string",
      "nullable": true,
      "description": "The seller's contracted share of this sale, echoed back from `transfer_data.amount`, in the base currency of the sale. Null on a checkout that carries no split, and on one that split the sale with `platform_fee` instead.",
      "example": "80000.00"
     }
    }
   },
   "CreateQuoteRequest": {
    "type": "object",
    "required": [
     "pricing",
     "payment_method",
     "to_currency"
    ],
    "properties": {
     "pricing": {
      "$ref": "#/components/schemas/MerchantIntent"
     },
     "payment_method": {
      "type": "string",
      "description": "Payment method (CARD, CRYPTO, BANK_TRANSFER, MOBILE_MONEY)"
     },
     "to_currency": {
      "type": "string",
      "description": "Currency code (e.g., 'USD', 'NGN', 'TZS', 'USDT_TRC20')"
     },
     "payment_rail": {
      "type": "string",
      "description": "Selected payment rail identifier. Fetch available rails by calling GET /v1/payments/rails?payment_method={method}&currency={currency}. Use the 'id' field from the response. Required when multiple rails are available for the payment method and currency combination."
     },
     "customer_email": {
      "type": "string",
      "format": "email",
      "maxLength": 255,
      "description": "Customer email address (optional; defaults to system identity for provider-specific quotes)"
     },
     "customer_name": {
      "type": "string",
      "maxLength": 255,
      "description": "Customer name (optional; defaults to a system identity when omitted)"
     }
    }
   },
   "QuoteResponse": {
    "type": "object",
    "description": "External response for quote (all payment methods) - excludes provider and gateway details",
    "properties": {
     "quote_id": {
      "type": "string",
      "description": "Quote ID (gateway-specific or internal)",
      "example": "quote_1a2b3c4d5e6f"
     },
     "payment_method": {
      "type": "string",
      "description": "Payment method used to generate quote",
      "example": "BANK_TRANSFER"
     },
     "payment_rail": {
      "type": "string",
      "description": "Payment rail used to generate quote",
      "example": "rail_123"
     },
     "base_amount_usd": {
      "type": "string",
      "description": "Base USD amount before fees",
      "example": "50.00"
     },
     "amount_local_base": {
      "type": "string",
      "description": "Amount in local currency (what customer pays)",
      "example": "75000.00"
     },
     "currency": {
      "type": "string",
      "description": "Local currency code (e.g., 'NGN', 'TZS', 'USD')",
      "example": "NGN"
     },
     "processing_fee": {
      "type": "string",
      "description": "Processing fee amount (as string)",
      "example": "750.00"
     },
     "exchange_rate": {
      "type": "string",
      "description": "Exchange rate (Decimal as string, if applicable)",
      "example": "1500.00"
     },
     "total_amount": {
      "type": "string",
      "description": "Total amount customer pays (base + fee)",
      "example": "75750.00"
     },
     "payment_type": {
      "type": "string",
      "enum": [
       "deposit",
       "withdrawal"
      ],
      "description": "Which direction this quote prices. `deposit`: money coming in from a customer. `withdrawal`: money going out to a destination.",
      "example": "deposit"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "Quote expiration time (ISO datetime)",
      "example": "2026-01-24T14:30:30.000Z"
     },
     "customer_bears_fee": {
      "type": "boolean",
      "description": "Whether customer bears the fee",
      "example": true
     }
    }
   },
   "ChargeStatusResponse": {
    "type": "object",
    "description": "Complete payment details including current status, payment information, and status history",
    "properties": {
     "charge_id": {
      "type": "string",
      "description": "Unique identifier for this payment/payment. Use this ID to track the payment status.",
      "example": "ch_1a2b3c4d5e6f"
     },
     "organization_id": {
      "type": "string",
      "description": "Organization ID that created this payment.",
      "example": "acct_7KpQ2mNv4XbR9dLc"
     },
     "customer_id": {
      "type": "string",
      "description": "Customer identifier associated with this payment.",
      "example": "cust_xyz789"
     },
     "amount": {
      "type": "string",
      "description": "Amount the customer paid, in the payment currency. This is a decimal string for precision.",
      "example": "75000.00"
     },
     "currency": {
      "type": "string",
      "description": "Currency code that the customer paid in (e.g., 'NGN', 'USD', 'GHS').",
      "example": "NGN"
     },
     "settlement_currency": {
      "type": "string",
      "description": "Currency code you will receive settlement in. This may differ from the payment currency.",
      "example": "NGN"
     },
     "settlement_amount": {
      "type": "string",
      "description": "Amount you will receive after fees are deducted, in settlement_currency. This is a decimal string for precision.",
      "example": "74250.00"
     },
     "status": {
      "type": "string",
      "enum": [
       "created",
       "processing",
       "succeeded",
       "accepted",
       "underpaid",
       "overpaid",
       "failed",
       "expired",
       "cancelled",
       "refunded",
       "partially_refunded",
       "auto_refunded"
      ],
      "description": "Current status of the charge. `created`: the charge exists and no attempt has succeeded yet. `processing`: an attempt is in flight with the provider. `succeeded`: an attempt succeeded and the charge is paid in full. `accepted`: an underpayment or overpayment was accepted as final settlement. `underpaid`: the customer paid less than the amount owed. `overpaid`: the customer paid more than the amount owed. `failed`: every attempt failed, or the charge was given up on. `expired`: the payment window elapsed before any payment arrived. `cancelled`: cancelled before any payment succeeded. `refunded`: the full amount was returned to the customer. `partially_refunded`: part of the amount was returned to the customer. `auto_refunded`: we automatically returned the full amount to the customer.",
      "example": "succeeded"
     },
     "metadata": {
      "type": "object",
      "description": "Custom metadata you provided when creating the checkout. This can include order IDs, product SKUs, or any other relevant information.",
      "additionalProperties": true,
      "example": {
       "order_id": "ORD-12345",
       "product_sku": "PREMIUM-ANNUAL"
      }
     },
     "status_history": {
      "type": "array",
      "description": "Every status this charge has held, oldest first. Read it to reconstruct the lifecycle when you missed a webhook.",
      "items": {
       "type": "object",
       "description": "A single status change on the charge.",
       "properties": {
        "status": {
         "type": "string",
         "description": "The status the charge moved to, from the same set as `status`.",
         "example": "succeeded"
        },
        "occurred_at": {
         "type": "string",
         "format": "date-time",
         "description": "ISO 8601 timestamp of when the charge moved to this status.",
         "example": "2026-01-24T14:35:00.000Z"
        },
        "reason": {
         "type": "string",
         "nullable": true,
         "description": "Why the charge moved to this status, when we have a reason to give. `null` otherwise.",
         "example": "Payment received and confirmed"
        }
       }
      }
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp when the payment was created.",
      "example": "2026-01-24T14:30:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp when the payment was last updated.",
      "example": "2026-01-24T14:35:00.000Z"
     }
    }
   },
   "PaymentMethodsResponse": {
    "type": "object",
    "description": "Response containing supported payment methods.",
    "properties": {
     "payment_methods": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "id": {
         "type": "string",
         "description": "Payment method identifier."
        },
        "display_name": {
         "type": "string",
         "description": "Human-readable payment method name."
        },
        "icon": {
         "type": "string",
         "description": "Icon or token representing the method."
        },
        "description": {
         "type": "string",
         "description": "Developer-facing payment method description."
        },
        "type": {
         "type": "string",
         "description": "Method type (for example `fiat` or `crypto`)."
        },
        "enabled_by_default": {
         "type": "boolean",
         "description": "Whether enabled by default for accounts."
        },
        "currencies": {
         "type": "array",
         "items": {
          "type": "string"
         },
         "description": "Currencies supported for this method."
        }
       },
       "required": [
        "id",
        "display_name",
        "icon",
        "description",
        "type",
        "enabled_by_default",
        "currencies"
       ]
      },
      "description": "List of payment methods available to the authenticated account in the current environment."
     }
    },
    "required": [
     "payment_methods"
    ]
   },
   "SupportedCurrenciesResponse": {
    "type": "object",
    "description": "Response containing all supported currencies organized by type (fiat and cryptocurrency)",
    "properties": {
     "fiat": {
      "type": "array",
      "description": "List of supported fiat (traditional) currencies. These are government-issued currencies like USD, NGN, GHS.",
      "items": {
       "type": "string",
       "description": "Fiat currency code (e.g., 'USD', 'NGN', 'GHS', 'KES', 'ZAR')",
       "example": "NGN"
      }
     },
     "crypto": {
      "type": "array",
      "description": "List of supported cryptocurrency codes. These may include network identifiers (e.g., 'USDT_TRC20' for Tron network, 'USDT_ERC20' for Ethereum network).",
      "items": {
       "type": "string",
       "description": "Cryptocurrency code, optionally including network (e.g., 'USDT_TRC20', 'USDT_ERC20', 'BTC')",
       "example": "USDT_TRC20"
      }
     }
    }
   },
   "AccountBalanceResponse": {
    "type": "object",
    "description": "Organization balance snapshot across currencies, including spendable and in-flight amounts.",
    "properties": {
     "account_id": {
      "type": "string",
      "description": "Organization ID the returned balances belong to.",
      "example": "acct_7KpQ2mNv4XbR9dLc"
     },
     "balances": {
      "type": "array",
      "description": "One balance object per currency bucket.",
      "items": {
       "type": "object",
       "properties": {
        "currency": {
         "type": "string",
         "description": "Currency code for this bucket (ISO 4217 or configured crypto code).",
         "example": "NGN"
        },
        "available_balance": {
         "type": "string",
         "description": "Amount currently available for new operations in this currency.",
         "example": "250000.00"
        },
        "pending_balance": {
         "type": "string",
         "description": "In-flight amount not yet available for spending.",
         "example": "15000.00"
        }
       },
       "required": [
        "currency",
        "available_balance",
        "pending_balance"
       ]
      }
     },
     "total_balance_usd": {
      "type": "string",
      "description": "Aggregate of available and pending balances converted to USD.",
      "example": "1375.00"
     },
     "pending_settlements_by_day": {
      "type": "array",
      "description": "Upcoming settlements grouped by day. Empty when no settlements are pending. Each entry describes settlements expected to become available on a given date.",
      "items": {
       "type": "object"
      },
      "example": []
     }
    },
    "required": [
     "account_id",
     "balances",
     "total_balance_usd"
    ]
   },
   "PayoutSupportedCurrenciesResponse": {
    "type": "object",
    "description": "Currencies currently supported for payout flows, grouped by type.",
    "properties": {
     "fiat": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Payout-supported fiat currencies."
     },
     "crypto": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Payout-supported crypto currencies."
     }
    },
    "required": [
     "fiat",
     "crypto"
    ]
   },
   "PayoutQuoteRequest": {
    "type": "object",
    "required": [
     "from_currency",
     "to_currency",
     "amount"
    ],
    "properties": {
     "from_currency": {
      "type": "string",
      "description": "Currency to debit from balance."
     },
     "to_currency": {
      "type": "string",
      "description": "Destination payout currency."
     },
     "amount": {
      "type": "string",
      "description": "Amount in `from_currency` to quote."
     },
     "payout_method": {
      "type": "string",
      "nullable": true,
      "description": "Optional payout method hint."
     }
    }
   },
   "PayoutQuoteResponse": {
    "type": "object",
    "description": "Response containing payout quote details.",
    "properties": {
     "quote_id": {
      "type": "string",
      "description": "Payout quote ID."
     },
     "from_currency": {
      "type": "string",
      "description": "Debited currency."
     },
     "to_currency": {
      "type": "string",
      "description": "Destination currency."
     },
     "from_amount": {
      "type": "string",
      "description": "The amount debited from your balance in `from_currency`, before the withdrawal fee is deducted."
     },
     "to_amount": {
      "type": "string",
      "description": "The amount the destination will receive in `to_currency`, net of the withdrawal fee. This is NOT a gross currency conversion of `from_amount`: the fee is deducted from `from_amount` before the exchange rate is applied, so `to_amount` already reflects what lands on the other side."
     },
     "exchange_rate": {
      "type": "string",
      "description": "Applied quote exchange rate."
     },
     "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "Quote expiration timestamp."
     }
    },
    "required": [
     "quote_id",
     "from_currency",
     "to_currency",
     "from_amount",
     "to_amount",
     "exchange_rate",
     "expires_at"
    ]
   },
   "BankAccountResolveRequest": {
    "type": "object",
    "required": [
     "bank_code",
     "account_number"
    ],
    "properties": {
     "bank_code": {
      "type": "string",
      "minLength": 1,
      "maxLength": 20,
      "description": "Bank code (e.g., '033')"
     },
     "account_number": {
      "type": "string",
      "minLength": 1,
      "maxLength": 50,
      "description": "Account number to resolve"
     }
    }
   },
   "BankAccountResolveResponse": {
    "type": "object",
    "description": "Response containing bank account validation and resolution details",
    "properties": {
     "status": {
      "type": "boolean",
      "description": "Whether the bank account was successfully resolved. true if account details are valid, false if invalid.",
      "example": true
     },
     "message": {
      "type": "string",
      "description": "Human-readable message describing the resolution result.",
      "example": "Account resolved successfully"
     },
     "data": {
      "type": "object",
      "nullable": true,
      "description": "Resolved bank account details. Only present when status is true. Contains account_name, bank_name, and other validated information.",
      "additionalProperties": true,
      "example": {
       "account_number": "0123456789",
       "account_name": "JOHN DOE",
       "bank_code": "058",
       "bank_name": "Guaranty Trust Bank"
      }
     },
     "error": {
      "type": "string",
      "nullable": true,
      "description": "Error message if account resolution failed. Only present when status is false.",
      "example": null
     }
    }
   },
   "BankListResponse": {
    "type": "object",
    "description": "Response containing bank list results.",
    "properties": {
     "status": {
      "type": "boolean",
      "description": "Whether the request succeeded."
     },
     "message": {
      "type": "string",
      "description": "Human-readable response message."
     },
     "data": {
      "type": "array",
      "nullable": true,
      "description": "Bank records when available.",
      "items": {
       "type": "object",
       "properties": {
        "name": {
         "type": "string",
         "description": "Bank display name."
        },
        "slug": {
         "type": "string",
         "description": "Provider-specific stable slug for the bank."
        },
        "code": {
         "type": "string",
         "description": "Bank code used for payout account resolution."
        },
        "nibss_bank_code": {
         "type": "string",
         "nullable": true,
         "description": "NIBSS bank code where applicable."
        },
        "country": {
         "type": "string",
         "description": "Country code where the bank operates."
        }
       },
       "required": [
        "name",
        "slug",
        "code",
        "country"
       ]
      }
     },
     "error": {
      "type": "string",
      "nullable": true,
      "description": "Error details when request fails."
     }
    },
    "required": [
     "status",
     "message"
    ]
   },
   "PayoutResponse": {
    "type": "object",
    "description": "The one shape a payout has on this API, across create, retrieve and list. `amount` is denominated in `currency`; `fee` and `total_debited` are denominated in `source_currency`. The two differ on every cross-currency payout, so the debit side must say which one it is in. For a same-currency payout `source_currency` equals `currency`.",
    "required": [
     "id",
     "status",
     "amount",
     "currency"
    ],
    "properties": {
     "id": {
      "type": "string",
      "description": "The payout ID. Use this to look it up with Get Payout.",
      "example": "pay_4Xr9dLc0mNv7Kq2B"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "processing",
       "completed",
       "failed"
      ],
      "description": "`pending`: accepted and queued. `processing`: submitted to the payment rail. `completed`: delivered to the destination. `failed`: could not be delivered, see `failure_reason`.",
      "example": "pending"
     },
     "amount": {
      "type": "string",
      "description": "The net amount delivered to the destination, in `currency`.",
      "example": "5000.00"
     },
     "currency": {
      "type": "string",
      "description": "The destination's currency. `amount` is denominated in this currency.",
      "example": "NGN"
     },
     "source_currency": {
      "type": "string",
      "description": "The currency of the balance being debited. `fee` and `total_debited` are denominated in this currency. Equal to `currency` for a same-currency payout; different for a cross-currency payout funded with a `quote_id`.",
      "example": "NGN",
      "nullable": true
     },
     "fee": {
      "type": "string",
      "description": "The fee charged for this payout, in `source_currency`.",
      "example": "100.00",
      "nullable": true
     },
     "total_debited": {
      "type": "string",
      "description": "The gross amount debited from your balance, in `source_currency`. Equals `amount` + `fee` only for a same-currency payout, because on a cross-currency payout `amount` is in a different currency, so the two do not add up.",
      "example": "5100.00",
      "nullable": true
     },
     "destination": {
      "type": "string",
      "description": "The payout destination ID this payout was sent to.",
      "example": "pd_7Kq2mNv4XbR9dLc0",
      "nullable": true
     },
     "reference": {
      "type": "string",
      "nullable": true,
      "description": "The reference you set when you created the payout. `null` if you set none.",
      "example": "payout-2026-08-07-001"
     },
     "failure_reason": {
      "type": "string",
      "nullable": true,
      "description": "Populated only when `status` is `failed`.",
      "example": null
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 creation timestamp.",
      "example": "2026-08-07T14:30:00.000Z"
     },
     "completed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp of when the payout reached a terminal state. `null` while `status` is `pending` or `processing`.",
      "example": null
     }
    }
   },
   "PayoutListResponse": {
    "type": "object",
    "description": "Response containing paginated list of payouts/withdrawals",
    "properties": {
     "total": {
      "type": "integer",
      "description": "Total number of payouts matching the query criteria, across all pages.",
      "example": 45
     },
     "items": {
      "type": "array",
      "description": "Array of payout objects for the current page",
      "items": {
       "$ref": "#/components/schemas/PayoutResponse"
      }
     }
    }
   },
   "PaymentRailOption": {
    "type": "object",
    "description": "Supported payment rail option",
    "properties": {
     "id": {
      "type": "string",
      "description": "Rail identifier. Use this value as the 'payment_rail' parameter when creating quotes.",
      "example": "bank_transfer_ng"
     },
     "name": {
      "type": "string",
      "nullable": true,
      "description": "Human-readable rail name",
      "example": "Bank Transfer Nigeria"
     },
     "active": {
      "type": "boolean",
      "nullable": true,
      "description": "Whether the rail is currently active and available for use",
      "example": true
     }
    },
    "required": [
     "id"
    ]
   },
   "PaymentRailsResponse": {
    "type": "object",
    "description": "Response containing available rails for a method and currency.",
    "properties": {
     "payment_method": {
      "type": "string",
      "description": "Payment method requested."
     },
     "currency": {
      "type": "string",
      "description": "Currency requested."
     },
     "country_code": {
      "type": "string",
      "nullable": true,
      "description": "Resolved country code for this rail lookup."
     },
     "rails": {
      "type": "array",
      "description": "Available rails for this method and currency.",
      "items": {
       "$ref": "#/components/schemas/PaymentRailOption"
      }
     }
    },
    "required": [
     "payment_method",
     "currency",
     "rails"
    ]
   },
   "ConversionQuoteRequest": {
    "type": "object",
    "required": [
     "from_currency",
     "to_currency",
     "amount"
    ],
    "properties": {
     "from_currency": {
      "type": "string",
      "description": "Currency to convert from (must be a settlement currency: USD or NGN)",
      "example": "USD"
     },
     "to_currency": {
      "type": "string",
      "description": "Currency to convert to (must be a settlement currency: USD or NGN)",
      "example": "NGN"
     },
     "amount": {
      "type": "string",
      "description": "Amount to convert as a decimal string",
      "example": "1000.00"
     }
    }
   },
   "ConversionQuoteResponse": {
    "type": "object",
    "description": "Response containing conversion quote with exchange rate and amounts",
    "properties": {
     "quote_id": {
      "type": "string",
      "description": "Unique identifier for this conversion quote. Use this ID when executing the conversion.",
      "example": "cqt_1a2b3c4d5e6f"
     },
     "from_currency": {
      "type": "string",
      "description": "Currency being converted from",
      "example": "USD"
     },
     "to_currency": {
      "type": "string",
      "description": "Currency being converted to",
      "example": "NGN"
     },
     "from_amount": {
      "type": "string",
      "description": "Amount in from_currency as a decimal string",
      "example": "1000.00"
     },
     "to_amount": {
      "type": "string",
      "description": "Amount in to_currency as a decimal string",
      "example": "1500000.00"
     },
     "exchange_rate": {
      "type": "string",
      "description": "Exchange rate applied (1 from_currency = X to_currency)",
      "example": "1500.00"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp when this quote expires",
      "example": "2026-01-24T14:31:00.000Z"
     }
    },
    "required": [
     "quote_id",
     "from_currency",
     "to_currency",
     "from_amount",
     "to_amount",
     "exchange_rate",
     "expires_at"
    ]
   },
   "ConversionCreateRequest": {
    "type": "object",
    "required": [
     "from_currency",
     "to_currency",
     "amount",
     "quote_id"
    ],
    "properties": {
     "from_currency": {
      "type": "string",
      "description": "Currency to convert from (must match the quote)",
      "example": "USD"
     },
     "to_currency": {
      "type": "string",
      "description": "Currency to convert to (must match the quote)",
      "example": "NGN"
     },
     "amount": {
      "type": "string",
      "description": "Amount to convert as a decimal string (must match the quote)",
      "example": "1000.00"
     },
     "quote_id": {
      "type": "string",
      "description": "Quote ID from the create conversion quote endpoint",
      "example": "cqt_1a2b3c4d5e6f"
     }
    }
   },
   "ConversionResponse": {
    "type": "object",
    "description": "Response containing executed conversion details",
    "properties": {
     "conversion_id": {
      "type": "string",
      "description": "Unique identifier for this conversion transaction",
      "example": "cvt_1a2b3c4d5e6f"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "completed",
       "failed"
      ],
      "description": "Status of the conversion. `pending` = in progress (typically seconds to minutes); `completed` = conversion successful and rate is final; `failed` = conversion could not be completed.",
      "example": "completed"
     },
     "from_currency": {
      "type": "string",
      "description": "Currency that was converted from",
      "example": "USD"
     },
     "to_currency": {
      "type": "string",
      "description": "Currency that was converted to",
      "example": "NGN"
     },
     "from_amount": {
      "type": "string",
      "description": "Amount converted from as a decimal string",
      "example": "1000.00"
     },
     "to_amount": {
      "type": "string",
      "description": "Amount converted to as a decimal string",
      "example": "1500000.00"
     },
     "exchange_rate": {
      "type": "string",
      "description": "Exchange rate that was applied",
      "example": "1500.00"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp when the conversion was executed",
      "example": "2026-01-24T14:30:00.000Z"
     },
     "quote_id": {
      "type": "string",
      "nullable": true,
      "description": "Quote identifier used for this conversion, if conversion was executed from a quote."
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "description": "Optional metadata associated with the conversion."
     }
    },
    "required": [
     "conversion_id",
     "status",
     "from_currency",
     "to_currency",
     "from_amount",
     "to_amount",
     "exchange_rate",
     "created_at"
    ]
   },
   "ConversionListResponse": {
    "type": "object",
    "properties": {
     "total": {
      "type": "integer",
      "description": "Total number of conversions that match the filter criteria."
     },
     "limit": {
      "type": "integer",
      "description": "Maximum number of conversion records returned in this page."
     },
     "offset": {
      "type": "integer",
      "description": "Number of conversion records skipped before this page."
     },
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ConversionResponse"
      },
      "description": "Paginated conversion records."
     }
    },
    "required": [
     "total",
     "limit",
     "offset",
     "items"
    ]
   },
   "OrganizationResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "description": "Unique identifier for the account.",
      "example": "acct_7KpQ2mNv4XbR9dLc"
     },
     "name": {
      "type": "string",
      "nullable": true,
      "description": "The account's display name.",
      "example": "Ada Stores"
     },
     "owner_user_id": {
      "type": "string",
      "description": "The user that owns the account. For an account you own this is a service user Bachs created; you never authenticate as it.",
      "example": "usr_7b3e19d24c0a"
     },
     "parent_organization_id": {
      "type": "string",
      "nullable": true,
      "description": "The platform this account is connected to, or `null` when it is a platform in its own right.",
      "example": "acct_7KpQ2mNv4XbR9dLc"
     },
     "country": {
      "type": "string",
      "nullable": true,
      "description": "Two-letter ISO 3166-1 country code. Decides which requirements the account is given.",
      "example": "NG"
     },
     "entity_type": {
      "type": "string",
      "enum": [
       "company",
       "individual"
      ],
      "nullable": true,
      "description": "What kind of legal person the account is, which together with `country` decides the requirements it is given. `company`: a registered entity, asked for registration and ownership details. `individual`: a natural person, asked only for their own identity.",
      "example": "company"
     },
     "fee_handling": {
      "type": "string",
      "enum": [
       "account_pays_fee",
       "customer_pays_fee"
      ],
      "description": "Who absorbs processing fees at checkout. `account_pays_fee`: deducted from the amount you receive. `customer_pays_fee`: added to what the customer pays.",
      "example": "account_pays_fee"
     },
     "enabled_payment_methods": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "One entry per exact corridor (`USD_CARD`, `NGN_CARD`, `NGN_BANK_TRANSFER`, `MOMO_GHS` to `MOMO_ZMW`, `CRYPTO`). See [payment method support](/guides/payments/payment-method-support). Each value has an `enabled` boolean; `CRYPTO` additionally carries a `currencies` map since it covers several asset/network pairs."
     },
     "adaptive_pricing": {
      "type": "boolean",
      "description": "When `true`, customers are shown prices in their local currency where one is available.",
      "example": true
     },
     "balance_currencies": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Currencies this account is configured to hold a balance in.",
      "example": [
       "NGN",
       "USD"
      ]
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "description": "Contact phone number, including country code.",
      "example": "+2348012345678"
     },
     "company_name": {
      "type": "string",
      "nullable": true,
      "description": "Registered company name, when the account is a company.",
      "example": "Ada Stores Limited"
     },
     "enabled_capabilities": {
      "type": "array",
      "nullable": true,
      "items": {
       "type": "string"
      },
      "description": "Names of the capabilities currently active on this account. A convenience view of `capabilities`.",
      "example": [
       "transfers",
       "payouts"
      ]
     },
     "capabilities": {
      "type": "object",
      "nullable": true,
      "additionalProperties": {
       "$ref": "#/components/schemas/AccountCapabilityStatus"
      },
      "description": "Each capability's status, keyed by capability name. Populated on single-account reads only; `null` on list items."
     },
     "requirements": {
      "allOf": [
       {
        "$ref": "#/components/schemas/AccountRequirements"
       }
      ],
      "nullable": true,
      "description": "Outstanding requirements for this account. Populated on single-account reads only; `null` on list items."
     },
     "is_active": {
      "type": "boolean",
      "description": "When `false`, the account is deactivated and cannot authenticate or move funds.",
      "example": true
     },
     "created_at": {
      "type": "string",
      "description": "When the account was created, ISO 8601 in UTC.",
      "example": "2026-08-01T09:12:44.000Z"
     },
     "updated_at": {
      "type": "string",
      "description": "When the account was last updated, ISO 8601 in UTC.",
      "example": "2026-08-07T11:04:22.518Z"
     },
     "responsibilities": {
      "allOf": [
       {
        "$ref": "#/components/schemas/ResponsibilitiesResponse"
       }
      ],
      "nullable": true,
      "description": "Fee arrangement for an account you own. `null` when this object is not an account you own."
     },
     "configuration": {
      "type": "object",
      "nullable": true,
      "additionalProperties": {
       "$ref": "#/components/schemas/AccountConfigurationOptions"
      },
      "description": "Personas applied to this account, keyed by name (`merchant`, `recipient`), each with an empty object as its value. Populated on single-account reads, where it is `{}` when none apply; `null` on list items.",
      "example": {
       "merchant": {},
       "recipient": {}
      }
     }
    }
   },
   "Error": {
    "type": "object",
    "description": "Standard error response format used across all API endpoints",
    "properties": {
     "detail": {
      "type": "string",
      "description": "Human-readable error message explaining what went wrong.",
      "example": "Invalid request parameters"
     },
     "error_code": {
      "type": "string",
      "description": "Machine-readable error code. Use this to handle errors programmatically. Common codes: VALIDATION_ERROR, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, TOO_MANY_REQUESTS, INTERNAL_SERVER_ERROR, BAD_GATEWAY, SERVICE_UNAVAILABLE.",
      "example": "VALIDATION_ERROR"
     },
     "errors": {
      "type": "array",
      "description": "Optional array of field-level validation errors. Only present for validation errors (400).",
      "items": {
       "type": "object",
       "properties": {
        "field": {
         "type": "string",
         "description": "The field that failed validation.",
         "example": "amount"
        },
        "message": {
         "type": "string",
         "description": "Description of the validation failure.",
         "example": "Amount must be a positive decimal string"
        },
        "type": {
         "type": "string",
         "description": "Error type identifier.",
         "example": "value_error"
        }
       },
       "required": [
        "field",
        "message",
        "type"
       ]
      }
     }
    },
    "required": [
     "detail",
     "error_code"
    ]
   },
   "SupportedPayoutCurrenciesByMethodResponse": {
    "type": "object",
    "description": "Payout currencies supported for a specific method.",
    "properties": {
     "method": {
      "type": "string",
      "description": "Requested payout method, normalized to uppercase."
     },
     "currencies": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Currencies available for this payout method."
     }
    },
    "required": [
     "method",
     "currencies"
    ]
   },
   "DisputeSummary": {
    "type": "object",
    "description": "Summary representation of a dispute record.",
    "properties": {
     "dispute_id": {
      "type": "string",
      "description": "Unique dispute identifier."
     },
     "charge_id": {
      "type": "string",
      "nullable": true,
      "description": "Associated payment/charge identifier, if linked."
     },
     "amount": {
      "type": "string",
      "description": "Disputed amount as a decimal string."
     },
     "currency": {
      "type": "string",
      "description": "ISO 4217 currency code for the disputed amount."
     },
     "status": {
      "type": "string",
      "description": "Current dispute status.",
      "enum": [
       "needs_response",
       "under_review",
       "won",
       "lost",
       "closed"
      ]
     },
     "is_response_editable": {
      "type": "boolean",
      "description": "Whether evidence can still be updated and submitted."
     },
     "reason": {
      "type": "string",
      "nullable": true,
      "description": "Dispute reason code reported by the payment network."
     },
     "response_deadline_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "Evidence submission deadline in ISO 8601 format."
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "Dispute creation timestamp."
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "Most recent update timestamp."
     }
    },
    "required": [
     "dispute_id",
     "amount",
     "currency",
     "status",
     "is_response_editable",
     "created_at",
     "updated_at"
    ]
   },
   "DisputeListResponse": {
    "type": "object",
    "description": "Paginated dispute list response.",
    "properties": {
     "total": {
      "type": "integer",
      "description": "Total number of disputes matching the query."
     },
     "items": {
      "type": "array",
      "description": "Dispute records for the requested page.",
      "items": {
       "$ref": "#/components/schemas/DisputeSummary"
      }
     }
    },
    "required": [
     "total",
     "items"
    ]
   },
   "DisputeEvidence": {
    "type": "object",
    "description": "Evidence fields attached to a dispute response.",
    "properties": {
     "access_activity_log": {
      "type": "string",
      "description": "An access or activity log showing the customer used what they paid for."
     },
     "billing_address": {
      "type": "string",
      "nullable": true,
      "description": "Customer's billing address."
     },
     "cancellation_policy_attachment_id": {
      "type": "string",
      "description": "Upload id of your cancellation policy document."
     },
     "cancellation_policy_disclosure": {
      "type": "string",
      "nullable": true,
      "description": "Cancellation policy shown to the customer."
     },
     "customer_communication_attachment_id": {
      "type": "string",
      "nullable": true,
      "description": "Uploaded customer communication document identifier."
     },
     "customer_email_address": {
      "type": "string",
      "nullable": true,
      "description": "Email address of the customer."
     },
     "customer_name": {
      "type": "string",
      "nullable": true,
      "description": "Full name of the customer."
     },
     "notes": {
      "type": "string",
      "nullable": true,
      "description": "Additional context supporting the dispute response."
     },
     "product_description": {
      "type": "string",
      "nullable": true,
      "description": "Description of delivered goods or services."
     },
     "refund_policy_attachment_id": {
      "type": "string",
      "description": "Upload id of your refund policy document."
     },
     "refund_policy_disclosure": {
      "type": "string",
      "nullable": true,
      "description": "Refund policy shown to the customer."
     },
     "refund_refusal_explanation": {
      "type": "string",
      "nullable": true,
      "description": "Reason a refund was not granted."
     },
     "service_date": {
      "type": "string",
      "nullable": true,
      "description": "Date the service was delivered."
     },
     "uncategorized_attachment_id": {
      "type": "string",
      "nullable": true,
      "description": "Uploaded supporting document identifier."
     }
    }
   },
   "DisputeSubmission": {
    "type": "object",
    "description": "Metadata for a dispute evidence submission attempt.",
    "properties": {
     "submission_id": {
      "type": "string",
      "description": "Unique identifier for this submission attempt."
     },
     "status": {
      "type": "string",
      "description": "Submission delivery status."
     },
     "trigger_source": {
      "type": "string",
      "description": "What triggered the submission attempt."
     },
     "submitted_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "Timestamp when submission was delivered."
     },
     "failed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "Timestamp when submission failed, if applicable."
     },
     "attempt_sequence": {
      "type": "integer",
      "description": "Submission attempt sequence number."
     }
    },
    "required": [
     "submission_id",
     "status",
     "trigger_source",
     "attempt_sequence"
    ]
   },
   "DisputeResponse": {
    "type": "object",
    "description": "Detailed dispute payload including evidence and latest submission metadata.",
    "properties": {
     "dispute_id": {
      "type": "string",
      "description": "Unique dispute identifier."
     },
     "charge_id": {
      "type": "string",
      "nullable": true,
      "description": "Associated payment/charge identifier, if linked."
     },
     "amount": {
      "type": "string",
      "description": "Disputed amount as a decimal string."
     },
     "currency": {
      "type": "string",
      "description": "ISO 4217 currency code for the disputed amount."
     },
     "status": {
      "type": "string",
      "description": "The current state of the dispute. A flat dispute fee is debited from your balance as soon as the dispute record is created, whichever of these states it starts in, and it is not charged again or refunded at resolution. `needs_response`: the dispute is open against you and you must submit evidence before `response_deadline_at`; no further funds have moved beyond that fee. `under_review`: your evidence has been submitted and the outcome is being decided; no further funds have moved beyond that fee. `won`: the dispute was decided in your favour and you keep the funds, and this state is terminal. `lost`: the dispute was decided against you, and the disputed amount is additionally debited from your balance, and this state is terminal. `closed`: the dispute was closed with no further action available to you, and this state is terminal.",
      "enum": [
       "needs_response",
       "under_review",
       "won",
       "lost",
       "closed"
      ],
      "example": "under_review"
     },
     "is_response_editable": {
      "type": "boolean",
      "description": "Whether evidence is still editable for this dispute."
     },
     "reason": {
      "type": "string",
      "nullable": true,
      "description": "Dispute reason code reported by the payment network."
     },
     "response_deadline_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "Evidence submission deadline in ISO 8601 format."
     },
     "evidence": {
      "$ref": "#/components/schemas/DisputeEvidence"
     },
     "latest_submission": {
      "allOf": [
       {
        "$ref": "#/components/schemas/DisputeSubmission"
       }
      ],
      "nullable": true,
      "description": "Most recent submission attempt for this dispute."
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "Dispute creation timestamp."
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "Most recent update timestamp."
     }
    },
    "required": [
     "dispute_id",
     "amount",
     "currency",
     "status",
     "is_response_editable",
     "evidence",
     "created_at",
     "updated_at"
    ]
   },
   "DisputeDocumentUploadResponse": {
    "type": "object",
    "description": "Successful dispute document upload response.",
    "properties": {
     "document_id": {
      "type": "string",
      "description": "Uploaded document identifier."
     },
     "file_name": {
      "type": "string",
      "description": "Original uploaded filename."
     },
     "mime_type": {
      "type": "string",
      "description": "Detected MIME type of the uploaded file."
     },
     "file_size_bytes": {
      "type": "integer",
      "description": "Uploaded file size in bytes."
     },
     "uploaded_at": {
      "type": "string",
      "format": "date-time",
      "description": "Upload completion timestamp."
     }
    },
    "required": [
     "document_id",
     "file_name",
     "mime_type",
     "file_size_bytes",
     "uploaded_at"
    ]
   },
   "DisputeEvidenceUpdateRequest": {
    "type": "object",
    "description": "Fields used to create or update dispute evidence. Include only fields that should change.",
    "properties": {
     "access_activity_log": {
      "type": "string",
      "description": "An access or activity log showing the customer used what they paid for."
     },
     "billing_address": {
      "type": "string",
      "description": "Customer's billing address."
     },
     "cancellation_policy_attachment_id": {
      "type": "string",
      "description": "Upload id of your cancellation policy document."
     },
     "cancellation_policy_disclosure": {
      "type": "string",
      "description": "Cancellation policy shown to the customer."
     },
     "customer_communication_attachment_id": {
      "type": "string",
      "description": "Uploaded customer communication document identifier."
     },
     "customer_email_address": {
      "type": "string",
      "description": "Email address of the customer."
     },
     "customer_name": {
      "type": "string",
      "description": "Full name of the customer."
     },
     "notes": {
      "type": "string",
      "description": "Additional context supporting the dispute response."
     },
     "product_description": {
      "type": "string",
      "description": "Description of delivered goods or services."
     },
     "refund_policy_attachment_id": {
      "type": "string",
      "description": "Upload id of your refund policy document."
     },
     "refund_policy_disclosure": {
      "type": "string",
      "description": "Refund policy shown to the customer."
     },
     "refund_refusal_explanation": {
      "type": "string",
      "description": "Reason a refund was not granted."
     },
     "service_date": {
      "type": "string",
      "description": "Date the service was delivered."
     },
     "uncategorized_attachment_id": {
      "type": "string",
      "description": "Uploaded supporting document identifier."
     }
    }
   },
   "DisputeEvidenceUpdateResponse": {
    "type": "object",
    "description": "Response after saving dispute evidence fields.",
    "properties": {
     "dispute_id": {
      "type": "string",
      "description": "The dispute that was updated."
     },
     "status": {
      "type": "string",
      "description": "Current dispute status after update."
     },
     "is_response_editable": {
      "type": "boolean",
      "description": "Whether the dispute is still editable after update."
     },
     "evidence_updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "Timestamp when evidence was last updated."
     }
    },
    "required": [
     "dispute_id",
     "status",
     "is_response_editable",
     "evidence_updated_at"
    ]
   },
   "DisputeSubmitResponse": {
    "type": "object",
    "description": "Response returned after submitting dispute evidence for review.",
    "properties": {
     "dispute_id": {
      "type": "string",
      "description": "The dispute that was submitted."
     },
     "status": {
      "type": "string",
      "description": "Updated dispute status after submission."
     },
     "is_response_editable": {
      "type": "boolean",
      "description": "Whether the dispute remains editable after submission."
     },
     "submission": {
      "type": "object",
      "description": "Metadata for the submission attempt created by this request.",
      "properties": {
       "submission_id": {
        "type": "string",
        "description": "Unique identifier for this submission attempt."
       },
       "submission_status": {
        "type": "string",
        "description": "Submission delivery outcome."
       },
       "trigger_source": {
        "type": "string",
        "description": "Source of submission trigger."
       },
       "submitted_at": {
        "type": "string",
        "format": "date-time",
        "nullable": true,
        "description": "Timestamp when submission was delivered."
       }
      },
      "required": [
       "submission_id",
       "submission_status",
       "trigger_source"
      ]
     }
    },
    "required": [
     "dispute_id",
     "status",
     "is_response_editable",
     "submission"
    ]
   },
   "MediaItemResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "url": {
      "type": "string",
      "nullable": true
     },
     "file_name": {
      "type": "string"
     },
     "mime_type": {
      "type": "string"
     },
     "file_size_bytes": {
      "type": "integer"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "CreateProductRequest": {
    "type": "object",
    "required": [
     "name",
     "price"
    ],
    "properties": {
     "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "example": "Pro Plan",
      "description": "Display name of the product. Shown to customers at checkout."
     },
     "description": {
      "type": "string",
      "maxLength": 5000,
      "nullable": true,
      "description": "Optional description of the product. Shown to customers at checkout.",
      "example": "Monthly access to all Pro features."
     },
     "price": {
      "$ref": "#/components/schemas/PriceInput",
      "description": "Primary price for the product. Provide an `amount` as a decimal string and a `currency`.",
      "example": {
       "price_type": "fixed",
       "currency": "USD",
       "amount": "29.00"
      }
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "description": "Up to 20 key/value pairs for your own reference.",
      "example": {
       "order_id": "ORD-9876",
       "tier": "pro"
      }
     },
     "billing_cycle": {
      "allOf": [
       {
        "$ref": "#/components/schemas/SubscriptionCadence"
       }
      ],
      "nullable": true,
      "description": "How often the product bills. Provide a cadence to make the product recurring, or omit it for a one-time product."
     },
     "trial_period": {
      "allOf": [
       {
        "$ref": "#/components/schemas/TrialPeriod"
       }
      ],
      "nullable": true,
      "description": "A free trial before the first charge, given as a duration like `{ \"interval\": \"day\", \"frequency\": 14 }` for 14 days. The customer isn't charged until the trial ends. Only valid on a recurring product. Currently in beta."
     }
    }
   },
   "UpdateProductRequest": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "description": "New display name for the product."
     },
     "description": {
      "type": "string",
      "maxLength": 5000,
      "nullable": true,
      "description": "New description for the product."
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "description": "Replace the product's key-value metadata."
     },
     "media": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Ordered list of upload IDs. Replaces existing media."
     },
     "price": {
      "$ref": "#/components/schemas/UpdatePriceInput",
      "nullable": true,
      "description": "Price fields to update. Omit to leave price unchanged."
     },
     "billing_cycle": {
      "allOf": [
       {
        "$ref": "#/components/schemas/SubscriptionCadence"
       }
      ],
      "nullable": true,
      "description": "How often the product bills. Provide a cadence to make the product recurring, or omit it for a one-time product."
     },
     "trial_period": {
      "allOf": [
       {
        "$ref": "#/components/schemas/TrialPeriod"
       }
      ],
      "nullable": true,
      "description": "A free trial before the first charge, given as a duration like `{ \"interval\": \"day\", \"frequency\": 14 }` for 14 days. The customer isn't charged until the trial ends. Only valid on a recurring product. Currently in beta."
     }
    }
   },
   "ProductResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "prod_1a2b3c4d5e6f",
      "description": "Unique identifier for the product, prefixed with `prod_`."
     },
     "organization_id": {
      "type": "string",
      "description": "The account that owns the product.",
      "example": "acct_7KpQ2mNv4XbR9dLc"
     },
     "name": {
      "type": "string",
      "description": "Display name of the product.",
      "example": "Pro Plan"
     },
     "description": {
      "type": "string",
      "nullable": true,
      "description": "Optional description of the product. `null` when not set.",
      "example": "Monthly access to all Pro features."
     },
     "price": {
      "$ref": "#/components/schemas/PriceResponse",
      "description": "Primary price for the product, in the product's default currency.",
      "example": {
       "price_type": "fixed",
       "currency": "USD",
       "amount": "29.00"
      }
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "archived"
      ],
      "description": "Status of the product. `active`: Live and available for use in checkouts and subscriptions. `archived`: Retired. Kept for reference but not available for new purchases.",
      "example": "active"
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "description": "Your own key-value data attached to the product, returned unchanged.",
      "example": {
       "order_id": "ORD-9876",
       "tier": "pro"
      }
     },
     "media": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/MediaItemResponse"
      },
      "description": "Media items (images) attached to the product. Empty when none are set."
     },
     "actor_id": {
      "type": "string",
      "description": "Identifier of the user or key that created the product.",
      "example": "usr_abc123"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp when the product was created.",
      "example": "2026-07-13T14:00:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp when the product was last updated.",
      "example": "2026-07-13T14:00:00.000Z"
     },
     "archived_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "When set, the product is archived and cannot be used in new checkouts. `null` while the product is active.",
      "example": null
     },
     "billing_cycle": {
      "allOf": [
       {
        "$ref": "#/components/schemas/SubscriptionCadence"
       }
      ],
      "nullable": true,
      "description": "How often the product bills. Provide a cadence to make the product recurring, or omit it for a one-time product."
     },
     "trial_period": {
      "allOf": [
       {
        "$ref": "#/components/schemas/TrialPeriod"
       }
      ],
      "nullable": true,
      "description": "A free trial before the first charge, given as a duration like `{ \"interval\": \"day\", \"frequency\": 14 }` for 14 days. The customer isn't charged until the trial ends. Only valid on a recurring product. Currently in beta."
     },
     "prices": {
      "type": "array",
      "description": "All prices configured on the product, one per currency. Each has `currency`, `amount`, optional `minimum_amount` and `maximum_amount`, and `is_default`.",
      "items": {
       "type": "object"
      }
     },
     "total_payments": {
      "type": "integer",
      "description": "Running count of completed payments for this product. Starts at `0` and increments as customers pay.",
      "example": 0
     },
     "total_amount": {
      "type": "string",
      "description": "Running total collected for this product, as a decimal string in the product currency. Starts at `\"0.00\"`.",
      "example": "0.00"
     }
    }
   },
   "ProductListResponse": {
    "type": "object",
    "properties": {
     "pagination": {
      "$ref": "#/components/schemas/PaginationResponse",
      "description": "Pagination cursors and counts. See the Pagination guide."
     },
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ProductResponse"
      },
      "description": "The products on this page. Each item is a product object."
     }
    }
   },
   "CreateProductGroupRequest": {
    "type": "object",
    "required": [
     "name",
     "product_ids"
    ],
    "properties": {
     "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "example": "Pro Plan Billing Options",
      "description": "Label the customer sees above the plan choices when this bundle is offered at checkout. 1 to 255 characters."
     },
     "product_ids": {
      "type": "array",
      "minItems": 1,
      "items": {
       "type": "string"
      },
      "example": [
       "prod_1a2b3c4d5e6f",
       "prod_7g8h9i0j1k2l"
      ],
      "description": "The products to bundle, in the order you want them presented to the customer. Every ID must be a product on your own account, and at least one is required."
     }
    }
   },
   "UpdateProductGroupRequest": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "description": "Replacement label for the bundle, applied to every checkout that offers it from the moment the request succeeds. Omit to leave the current label alone.",
      "example": "Pro Plan Billing Options (2026)"
     },
     "product_ids": {
      "type": "array",
      "minItems": 1,
      "items": {
       "type": "string"
      },
      "description": "Replacement membership for the bundle. What you send becomes the complete list and the display order, so include every product you want to keep, not only the ones you are adding."
     }
    }
   },
   "ProductGroupResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "pgrp_9c4d1e7a2b8f6035a1d4",
      "description": "Pass this wherever a bundle is referenced: retrieving, updating, or deleting the group, and offering it at checkout."
     },
     "organization_id": {
      "type": "string",
      "description": "The account that owns the bundle. Only keys issued for that account, and for the same environment, can read or change it.",
      "example": "acct_7KpQ2mNv4XbR9dLc"
     },
     "name": {
      "type": "string",
      "description": "The label currently shown to the customer above the plan choices at checkout.",
      "example": "Pro Plan Billing Options"
     },
     "products": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ProductResponse"
      },
      "description": "Every member product in full, so you can render each plan choice without a second call. The order matches the `product_ids` you last sent."
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp, in UTC with milliseconds, of when the bundle was first created.",
      "example": "2026-07-13T14:00:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp of the most recent change to the label or the membership. It equals `created_at` until the first update.",
      "example": "2026-07-13T14:00:00.000Z"
     }
    }
   },
   "ProductGroupListResponse": {
    "type": "object",
    "properties": {
     "pagination": {
      "$ref": "#/components/schemas/PaginationResponse",
      "description": "Page counters and cursors for this result set. Send `next_cursor` back as the `cursor` query parameter to fetch the following page, and stop when `has_more` is `false`."
     },
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ProductGroupResponse"
      },
      "description": "The bundles on this page, each returned with its member products expanded in full."
     }
    }
   },
   "PaginationResponse": {
    "type": "object",
    "properties": {
     "next_cursor": {
      "type": "string",
      "nullable": true
     },
     "prev_cursor": {
      "type": "string",
      "nullable": true
     },
     "has_more": {
      "type": "boolean"
     },
     "limit": {
      "type": "integer"
     },
     "offset": {
      "type": "integer"
     },
     "returned": {
      "type": "integer"
     },
     "total": {
      "type": "integer"
     }
    }
   },
   "UploadResponse": {
    "type": "object",
    "description": "A stored file and its metadata.",
    "properties": {
     "upload_id": {
      "type": "string",
      "description": "Unique identifier for this upload. Pass it wherever an endpoint accepts a file reference.",
      "example": "upl_4f3e2d1c"
     },
     "file_name": {
      "type": "string",
      "description": "The file name you uploaded, preserved unchanged.",
      "example": "product-hero.png"
     },
     "mime_type": {
      "type": "string",
      "description": "The media type detected from the file's contents, which may differ from what its extension suggests.",
      "example": "image/png"
     },
     "file_size_bytes": {
      "type": "integer",
      "description": "Size of the stored file in bytes.",
      "example": 204800
     },
     "url": {
      "type": "string",
      "nullable": true,
      "description": "URL the file can be fetched from. `null` for a private upload, which is served only through the API.",
      "example": "https://cdn.bachs.io/uploads/upl_4f3e2d1c/product-hero.png"
     },
     "linked_resource_type": {
      "type": "string",
      "nullable": true,
      "description": "The kind of resource this upload is attached to, for example `product`. `null` while the upload is unattached.",
      "example": "product"
     },
     "linked_resource_id": {
      "type": "string",
      "nullable": true,
      "description": "ID of the resource this upload is attached to. `null` while the upload is unattached.",
      "example": "prod_abc123"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp of when the file was uploaded.",
      "example": "2026-02-22T12:00:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp of when the upload was last changed, which includes being attached to a resource.",
      "example": "2026-02-22T12:01:30.000Z"
     }
    },
    "required": [
     "upload_id",
     "file_name",
     "mime_type",
     "file_size_bytes",
     "created_at",
     "updated_at"
    ]
   },
   "UploadDeleteResponse": {
    "type": "object",
    "description": "Confirmation that an upload was deleted.",
    "properties": {
     "upload_id": {
      "type": "string",
      "description": "The upload that was deleted. It can no longer be attached to a resource.",
      "example": "upl_4f3e2d1c"
     },
     "deleted": {
      "type": "boolean",
      "description": "Always `true` on a successful delete. A file that was already gone returns `404` instead.",
      "example": true
     }
    },
    "required": [
     "upload_id",
     "deleted"
    ]
   },
   "CustomerListItem": {
    "type": "object",
    "properties": {
     "customer_id": {
      "type": "string",
      "example": "cust_1a2b3c4d5e6f",
      "description": "Unique identifier for the customer, prefixed with `cust_`."
     },
     "email": {
      "type": "string",
      "format": "email",
      "example": "jane@example.com",
      "description": "The customer's email address."
     },
     "name": {
      "type": "string",
      "nullable": true,
      "example": "Jane Doe",
      "description": "The customer's full name. `null` when not set."
     },
     "metadata": {
      "type": "object",
      "additionalProperties": true,
      "example": {},
      "description": "Your own key-value data attached to the customer."
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-01-24T12:00:00.000Z",
      "description": "ISO 8601 timestamp when the customer was created."
     }
    },
    "required": [
     "customer_id",
     "email",
     "metadata",
     "created_at"
    ]
   },
   "CustomerListResponse": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CustomerListItem"
      },
      "description": "The customers on this page. Each item is a customer object."
     },
     "pagination": {
      "type": "object",
      "properties": {
       "next_cursor": {
        "type": "string",
        "nullable": true
       },
       "prev_cursor": {
        "type": "string",
        "nullable": true
       },
       "has_more": {
        "type": "boolean"
       },
       "limit": {
        "type": "integer"
       },
       "offset": {
        "type": "integer"
       },
       "returned": {
        "type": "integer"
       },
       "total": {
        "type": "integer"
       }
      },
      "description": "Pagination cursors and counts. See the Pagination guide."
     }
    },
    "required": [
     "items",
     "pagination"
    ]
   },
   "PortalSessionResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "psn_9f2c4a7b1d3e",
      "description": "The session identifier, prefixed with `psn_`. Use it to correlate a session with your own logs; it is not a credential and cannot be exchanged for access."
     },
     "url": {
      "type": "string",
      "format": "uri",
      "example": "https://portal.bachs.io/s/6Yc0nQpR2vX1sK7fLbA9tE",
      "description": "The URL that opens the portal as this customer. It carries the session credential, so it works on any device and must not be logged or shared."
     }
    },
    "required": [
     "id",
     "url"
    ]
   },
   "CustomerDetailResponse": {
    "type": "object",
    "properties": {
     "customer_id": {
      "type": "string",
      "example": "cust_1a2b3c4d5e6f",
      "description": "Unique identifier for the customer, prefixed with `cust_`."
     },
     "email": {
      "type": "string",
      "format": "email",
      "example": "jane@example.com",
      "description": "The customer's email address."
     },
     "name": {
      "type": "string",
      "nullable": true,
      "example": "Jane Doe",
      "description": "The customer's full name. `null` when not set."
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "description": "The customer's phone number in E.164 format, e.g. `+2348012345678`.",
      "example": "+2348012345678"
     },
     "metadata": {
      "type": "object",
      "additionalProperties": true,
      "example": {
       "plan": "pro"
      },
      "description": "Your own key-value data attached to the customer."
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-01-24T12:00:00.000Z",
      "description": "ISO 8601 timestamp when the customer was created."
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "example": "2026-01-24T12:00:00.000Z",
      "description": "ISO 8601 timestamp when the customer was last updated."
     },
     "billing_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/CustomerBillingAddress"
       }
      ],
      "nullable": true,
      "description": "The customer's billing address, or `null` if none is set."
     }
    },
    "required": [
     "customer_id",
     "email",
     "metadata",
     "created_at",
     "updated_at"
    ]
   },
   "CreateCustomerRequest": {
    "type": "object",
    "required": [
     "email"
    ],
    "properties": {
     "email": {
      "type": "string",
      "format": "email",
      "example": "jane@example.com",
      "description": "The customer's email address. Used to identify the customer and send receipts."
     },
     "name": {
      "type": "string",
      "nullable": true,
      "maxLength": 511,
      "example": "Jane Doe",
      "description": "The customer's full name. Derived from `first_name` and `last_name` when those are provided instead."
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "description": "The customer's phone number in E.164 format, e.g. `+2348012345678`.",
      "example": "+2348012345678"
     },
     "metadata": {
      "type": "object",
      "additionalProperties": true,
      "example": {
       "plan": "pro"
      },
      "description": "Your own key-value data attached to the customer, returned unchanged."
     },
     "billing_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/CustomerBillingAddress"
       }
      ],
      "nullable": true,
      "description": "The customer's billing address. Optional on create. `line1` and `country` are required whenever an address is supplied; `country` must be a real ISO-3166-1 alpha-2 code. An all-empty object is rejected; omit the field or send `null` instead."
     }
    }
   },
   "UpdateCustomerRequest": {
    "type": "object",
    "properties": {
     "email": {
      "type": "string",
      "format": "email",
      "nullable": true,
      "example": "jane@example.com",
      "description": "The customer's email address. Used to identify the customer and send receipts."
     },
     "name": {
      "type": "string",
      "nullable": true,
      "maxLength": 511,
      "example": "Jane Doe",
      "description": "The customer's full name. Derived from `first_name` and `last_name` when those are provided instead."
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "description": "The customer's phone number in E.164 format, e.g. `+2348012345678`.",
      "example": "+2348012345678"
     },
     "metadata": {
      "type": "object",
      "additionalProperties": true,
      "nullable": true,
      "example": {
       "plan": "pro"
      },
      "description": "Your own key-value data attached to the customer, returned unchanged."
     },
     "billing_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/CustomerBillingAddress"
       }
      ],
      "nullable": true,
      "description": "Omit this field to leave the billing address untouched. Send `null` to clear it. Send an object to replace it in full. This is not a merge, so any component you leave out of the object becomes `null`, even if a value was previously stored. `line1` and `country` are required whenever an object is supplied, and an all-empty object is rejected; use explicit `null` to clear the address instead. `name` and `phone_number` do not behave this way; updating those merges normally."
     }
    }
   },
   "CustomerBillingAddress": {
    "type": "object",
    "description": "A customer's billing address. Treated as one atomic value: on update, a supplied object replaces every component rather than merging with what's stored.",
    "properties": {
     "line1": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "example": "40 Yaba Road",
      "description": "Street address. Required whenever an address is supplied."
     },
     "line2": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "example": null,
      "description": "Apartment, suite, unit, etc. `null` when not set."
     },
     "city": {
      "type": "string",
      "nullable": true,
      "maxLength": 128,
      "example": "Lagos",
      "description": "City, district, or suburb."
     },
     "state": {
      "type": "string",
      "nullable": true,
      "maxLength": 128,
      "example": "Lagos",
      "description": "State, province, or region."
     },
     "postal_code": {
      "type": "string",
      "nullable": true,
      "maxLength": 32,
      "example": "101245",
      "description": "ZIP or postal code."
     },
     "country": {
      "type": "string",
      "nullable": true,
      "minLength": 2,
      "maxLength": 2,
      "example": "NG",
      "description": "Two-letter ISO-3166-1 alpha-2 country code. Required whenever an address is supplied."
     }
    }
   },
   "CurrencyOptionInput": {
    "type": "object",
    "required": [
     "currency"
    ],
    "properties": {
     "currency": {
      "type": "string",
      "example": "GHS",
      "description": "An additional currency to price this product in (`USD`, `NGN`, `GHS`, `KES`, `MWK`, `RWF`, `TZS`, `UGX`, `XAF`, `XOF`, `ZMW`). Cannot be the primary currency."
     },
     "amount": {
      "type": "string",
      "example": "29.00",
      "nullable": true,
      "description": "Price as a decimal string, e.g. `\"29.00\"`. Required when `price_type` is `fixed`. Omit for `free` and `custom`."
     },
     "preset_amount": {
      "type": "string",
      "nullable": true,
      "description": "Suggested amount prefilled at checkout for a custom price in this currency, as a decimal string. Only used when `price_type` is `custom`.",
      "example": "15.00"
     },
     "minimum_amount": {
      "type": "string",
      "nullable": true,
      "description": "Least the customer can pay, as a decimal string. Only used when `price_type` is `custom`. Set `\"0.00\"` to allow free (pay what you want).",
      "example": "5.00"
     },
     "maximum_amount": {
      "type": "string",
      "nullable": true,
      "description": "Most the customer can pay, as a decimal string. Only used when `price_type` is `custom`.",
      "example": "500.00"
     }
    }
   },
   "CurrencyOptionResponse": {
    "type": "object",
    "properties": {
     "currency": {
      "type": "string",
      "example": "GHS"
     },
     "amount": {
      "type": "string",
      "example": "35.00"
     },
     "minimum_amount": {
      "type": "string",
      "example": "5.00",
      "nullable": true
     },
     "maximum_amount": {
      "type": "string",
      "example": "500.00",
      "nullable": true
     }
    }
   },
   "PriceInput": {
    "type": "object",
    "required": [
     "currency"
    ],
    "properties": {
     "currency": {
      "type": "string",
      "enum": [
       "USD",
       "NGN",
       "GHS",
       "KES",
       "MWK",
       "RWF",
       "TZS",
       "UGX",
       "XAF",
       "XOF",
       "ZMW"
      ],
      "example": "USD",
      "description": "The product's primary currency, and the currency customers are charged in by default. Any supported currency is allowed, including one your account does not hold a balance in; those are converted when the payment settles. It cannot be repeated in `currency_options`."
     },
     "price_type": {
      "type": "string",
      "enum": [
       "fixed",
       "free",
       "custom"
      ],
      "description": "How the product is priced. `fixed`: a set amount, given in `amount`. `free`: no charge. `custom`: the customer pays what they want, bounded by `minimum_amount` and `maximum_amount` with an optional `preset_amount` suggestion.",
      "example": "fixed"
     },
     "amount": {
      "type": "string",
      "example": "29.00",
      "nullable": true,
      "description": "Price as a decimal string, e.g. `\"29.00\"`. Required when `price_type` is `fixed`. Omit for `free` and `custom`."
     },
     "preset_amount": {
      "type": "string",
      "nullable": true,
      "description": "Suggested amount prefilled at checkout for a custom price, as a decimal string. Only used when `price_type` is `custom`.",
      "example": "15.00"
     },
     "minimum_amount": {
      "type": "string",
      "nullable": true,
      "description": "Least the customer can pay, as a decimal string. Only used when `price_type` is `custom`. Set `\"0.00\"` to allow free (pay what you want).",
      "example": "5.00"
     },
     "maximum_amount": {
      "type": "string",
      "nullable": true,
      "description": "Most the customer can pay, as a decimal string. Only used when `price_type` is `custom`.",
      "example": "500.00"
     },
     "currency_options": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CurrencyOptionInput"
      },
      "nullable": true,
      "description": "Prices in other currencies. Each entry sets a price for one additional currency, and cannot repeat the primary currency.",
      "example": [
       {
        "currency": "NGN",
        "amount": "45000.00"
       }
      ]
     }
    }
   },
   "UpdatePriceInput": {
    "type": "object",
    "properties": {
     "amount": {
      "type": "string",
      "example": "29.00",
      "nullable": true,
      "description": "New price as a decimal in the major unit (e.g. `39.00`). Only valid for fixed-price products."
     },
     "currency_options": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CurrencyOptionInput"
      },
      "nullable": true,
      "description": "Full replacement of multi-currency prices. Omit to leave unchanged."
     }
    }
   },
   "PriceResponse": {
    "type": "object",
    "properties": {
     "currency": {
      "type": "string",
      "example": "USD"
     },
     "price_type": {
      "type": "string",
      "enum": [
       "fixed",
       "free",
       "custom"
      ],
      "description": "How the product is priced. `fixed`: a set amount, given in `amount`. `free`: no charge. `custom`: the customer pays what they want, bounded by `minimum_amount` and `maximum_amount` with an optional `preset_amount` suggestion.",
      "example": "fixed"
     },
     "amount": {
      "type": "string",
      "example": "29.00",
      "description": "Price in the primary currency as a decimal string."
     },
     "preset_amount": {
      "type": "string",
      "nullable": true,
      "description": "Suggested amount prefilled at checkout for a custom price, as a decimal string. Only used when `price_type` is `custom`.",
      "example": "15.00"
     },
     "minimum_amount": {
      "type": "string",
      "example": "5.00",
      "nullable": true,
      "description": "Minimum the customer must pay. Present only when `price_type` is `custom`."
     },
     "maximum_amount": {
      "type": "string",
      "example": "500.00",
      "nullable": true,
      "description": "Maximum the customer may pay. Present only when `price_type` is `custom`."
     },
     "currency_options": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CurrencyOptionResponse"
      }
     }
    }
   },
   "ResolvedProductItem": {
    "type": "object",
    "description": "A resolved product line item within a checkout session.",
    "properties": {
     "product_id": {
      "type": "string",
      "description": "Product identifier.",
      "example": "prod_abc123"
     },
     "product_name": {
      "type": "string",
      "description": "Product display name.",
      "example": "Premium Plan"
     },
     "quantity": {
      "type": "integer",
      "description": "Number of units.",
      "example": 1
     },
     "unit_amount": {
      "type": "string",
      "description": "Price per unit in `currency`.",
      "example": "50.00"
     },
     "currency": {
      "type": "string",
      "description": "Currency code for this line item.",
      "example": "USD"
     },
     "price_type": {
      "type": "string",
      "enum": [
       "fixed",
       "free",
       "custom"
      ],
      "description": "How the product is priced. `fixed`: a set amount, given in `amount`. `free`: no charge. `custom`: the customer pays what they want, bounded by `minimum_amount` and `maximum_amount` with an optional `preset_amount` suggestion.",
      "example": "fixed"
     },
     "minimum_amount": {
      "type": "string",
      "nullable": true,
      "description": "Minimum allowed amount when `price_type` is true.",
      "example": "10.00"
     },
     "maximum_amount": {
      "type": "string",
      "nullable": true,
      "description": "Maximum allowed amount when `price_type` is true.",
      "example": "500.00"
     },
     "line_total": {
      "type": "string",
      "description": "Total for this line item (`unit_amount` \u00d7 `quantity`).",
      "example": "50.00"
     }
    },
    "required": [
     "product_id",
     "product_name",
     "quantity",
     "unit_amount",
     "currency",
     "price_type",
     "line_total"
    ]
   },
   "CheckoutSessionApiResponse": {
    "type": "object",
    "description": "Checkout session details returned by `GET /v1/checkout-sessions/{checkout_id}`.",
    "properties": {
     "checkout_id": {
      "type": "string",
      "description": "Unique checkout identifier.",
      "example": "chk_1M2N3o4P5q6R7s8T"
     },
     "status": {
      "type": "string",
      "enum": [
       "open",
       "completed",
       "expired",
       "cancelled"
      ],
      "description": "Current lifecycle status of the checkout session. `open`: awaiting customer payment, where every new session starts. `completed`: payment succeeded, a terminal state. `expired`: the session window elapsed before payment, a terminal state. `cancelled`: cancelled before completion, a terminal state.",
      "example": "completed"
     },
     "recurring": {
      "allOf": [
       {
        "$ref": "#/components/schemas/CheckoutRecurring"
       }
      ],
      "nullable": true,
      "description": "Present only for a subscription checkout; `null` for a one-time checkout."
     },
     "payment_status": {
      "type": "string",
      "description": "Payment lifecycle for the checkout. `requires_payment_method`, `requires_confirmation`, `requires_action`, `processing`, `succeeded`, `failed`, or `canceled`.",
      "enum": [
       "requires_payment_method",
       "requires_confirmation",
       "requires_action",
       "processing",
       "succeeded",
       "failed",
       "canceled"
      ],
      "nullable": true,
      "example": "requires_payment_method"
     },
     "source_type": {
      "type": "string",
      "description": "What created the checkout, e.g. `CHECKOUT_SESSION` or `API`.",
      "example": "CHECKOUT_SESSION",
      "nullable": true
     },
     "amount": {
      "type": "string",
      "description": "Total amount in `currency`.",
      "example": "50.00"
     },
     "currency": {
      "type": "string",
      "description": "Base currency code.",
      "example": "USD"
     },
     "reference": {
      "type": "string",
      "nullable": true,
      "description": "The reference you set when you created the session. `null` if you set none.",
      "example": "order_9876"
     },
     "charge": {
      "allOf": [
       {
        "$ref": "#/components/schemas/PaymentResponse"
       }
      ],
      "nullable": true,
      "description": "The payment created by this checkout, once payment has been attempted. `null` before then."
     },
     "payment_method": {
      "type": "string",
      "description": "The payment method selected for the checkout, if any. For every method except card, this is the exact corridor collected, such as `NGN_BANK_TRANSFER`, `MOMO_GHS`, or `CRYPTO`. Card charges report `CARD` rather than `USD_CARD` or `NGN_CARD`; read the currency to tell which card corridor collected it.",
      "example": "NGN_BANK_TRANSFER",
      "nullable": true
     },
     "customer": {
      "$ref": "#/components/schemas/CheckoutCustomer"
     },
     "customer_details": {
      "allOf": [
       {
        "$ref": "#/components/schemas/CheckoutCustomerDetails"
       }
      ],
      "nullable": true,
      "description": "What the buyer supplied; present whenever an identity was collected, record or no record. `null` before then."
     },
     "success_url": {
      "type": "string",
      "nullable": true,
      "format": "uri",
      "description": "URL the customer is redirected to after successful payment.",
      "example": "https://yourapp.com/success"
     },
     "cancel_url": {
      "type": "string",
      "nullable": true,
      "format": "uri",
      "description": "URL the customer is redirected to if they cancel.",
      "example": "https://yourapp.com/cancel"
     },
     "products": {
      "type": "array",
      "nullable": true,
      "description": "Resolved product line items. Populated for `CART` sessions; may be `null` for `SELECTION` sessions before the customer picks a product.",
      "items": {
       "$ref": "#/components/schemas/ResolvedProductItem"
      }
     },
     "billing_currency": {
      "type": "string",
      "nullable": true,
      "description": "Currency the customer selected for billing.",
      "example": "NGN"
     },
     "platform_fee": {
      "type": "string",
      "nullable": true,
      "description": "The platform's cut of this sale, in the base currency of the sale. The key is always present; it reads `null`, not `\"0.00\"`, on a checkout that carries no fee, and on a checkout that split the sale with `transfer_data.amount` instead. See [Platform fees](/connect/platform-fees).",
      "example": "20000.00"
     },
     "destination_amount": {
      "type": "string",
      "nullable": true,
      "description": "The seller's contracted share of this sale, in the base currency of the sale. Null on a checkout that carries no split, and on one that split the sale with `platform_fee` instead.",
      "example": "80000.00"
     },
     "session_mode": {
      "type": "string",
      "description": "How products are presented. `CART` sums a fixed set of items; `SELECTION` lets the customer pick one from a group.",
      "enum": [
       "CART",
       "SELECTION"
      ],
      "nullable": true,
      "example": "CART"
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Public metadata you attached at session creation.",
      "example": {
       "order_id": "ORD-9876"
      }
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 creation timestamp.",
      "example": "2026-01-24T14:30:00.000Z"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 expiry timestamp.",
      "example": "2026-01-24T15:30:00.000Z"
     },
     "completed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when the session was completed.",
      "example": "2026-01-24T14:35:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 last-updated timestamp.",
      "example": "2026-01-24T14:35:00.000Z"
     }
    },
    "required": [
     "checkout_id",
     "status",
     "amount",
     "currency",
     "customer",
     "created_at",
     "updated_at"
    ]
   },
   "PaymentProductItem": {
    "type": "object",
    "description": "A product line item purchased in this payment.",
    "properties": {
     "product_id": {
      "type": "string",
      "description": "Product identifier.",
      "example": "prod_abc123"
     },
     "product_name": {
      "type": "string",
      "description": "Product display name.",
      "example": "Premium Plan"
     },
     "quantity": {
      "type": "integer",
      "description": "Number of units purchased.",
      "example": 1
     },
     "unit_amount": {
      "type": "string",
      "description": "Price per unit in `currency`.",
      "example": "50.00"
     },
     "currency": {
      "type": "string",
      "description": "Currency code for this line item.",
      "example": "USD"
     },
     "line_total": {
      "type": "string",
      "description": "Total for this line item (`unit_amount` \u00d7 `quantity`).",
      "example": "50.00"
     }
    },
    "required": [
     "product_id",
     "product_name",
     "quantity",
     "unit_amount",
     "currency",
     "line_total"
    ]
   },
   "SubscriptionCadence": {
    "type": "object",
    "properties": {
     "interval": {
      "type": "string",
      "enum": [
       "day",
       "week",
       "month",
       "year"
      ],
      "description": "Unit of time for each billing cycle. `day`: billed daily. `week`: billed weekly. `month`: billed monthly. `year`: billed yearly.",
      "example": "month"
     },
     "frequency": {
      "type": "integer",
      "description": "Number of intervals per cycle. For example, `interval` `month` with `frequency` `3` bills every three months.",
      "example": 1
     }
    }
   },
   "SubscriptionCatalogProduct": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "prod_abc123",
      "description": "Unique identifier for the product."
     },
     "name": {
      "type": "string",
      "description": "The product's name, shown to customers at checkout.",
      "example": "Pro plan"
     },
     "description": {
      "type": "string",
      "nullable": true,
      "description": "The product's description. `null` if none was set.",
      "example": "Everything in Basic, plus priority support."
     },
     "status": {
      "type": "string",
      "description": "Whether the product is active or archived.",
      "example": "active"
     },
     "billing_cycle": {
      "allOf": [
       {
        "$ref": "#/components/schemas/SubscriptionCadence"
       }
      ],
      "nullable": true
     },
     "trial_period": {
      "allOf": [
       {
        "$ref": "#/components/schemas/TrialPeriod"
       }
      ],
      "nullable": true
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the product was created, in UTC.",
      "example": "2026-03-01T12:00:00Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the product was last updated, in UTC.",
      "example": "2026-03-01T12:00:00Z"
     }
    }
   },
   "SubscriptionItemPrice": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "price_pro_usd",
      "description": "Unique identifier for the price."
     },
     "product_id": {
      "type": "string",
      "description": "The product this price belongs to.",
      "example": "prod_abc123"
     },
     "price_type": {
      "type": "string",
      "enum": [
       "fixed",
       "free",
       "custom"
      ],
      "description": "How this line item is priced. `fixed`: a set price per cycle, the same for every customer. `free`: no charge. `custom`: the customer chose the amount at checkout, within the product's bounds.",
      "example": "fixed"
     },
     "currency": {
      "type": "string",
      "description": "The currency of this price, as an ISO 4217 code.",
      "example": "USD"
     },
     "unit_amount": {
      "type": "string",
      "description": "Decimal string at the currency's precision",
      "example": "10.00"
     },
     "billing_cycle": {
      "allOf": [
       {
        "$ref": "#/components/schemas/SubscriptionCadence"
       }
      ],
      "nullable": true
     },
     "trial_period": {
      "allOf": [
       {
        "$ref": "#/components/schemas/TrialPeriod"
       }
      ],
      "nullable": true
     },
     "seat_tiers": {
      "type": "object",
      "nullable": true,
      "description": "Reserved for seat-based pricing. `null` for the standard pricing available today.",
      "example": null
     },
     "is_archived": {
      "type": "boolean",
      "description": "Whether the price has been archived. Archived prices keep billing existing subscribers but are not offered for new checkouts.",
      "example": false
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the price was created, in UTC.",
      "example": "2026-03-01T12:00:00Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the price was last updated, in UTC.",
      "example": "2026-03-01T12:00:00Z"
     }
    }
   },
   "SubscriptionItem": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "si_11aa22bb",
      "description": "Unique identifier for the line item."
     },
     "status": {
      "type": "string",
      "description": "Lifecycle status of the item. Follows the parent subscription's status.",
      "example": "active"
     },
     "quantity": {
      "type": "integer",
      "description": "The billed quantity for this item.",
      "example": 1
     },
     "recurring": {
      "type": "boolean",
      "description": "Whether this item recurs each billing cycle. Always `true` for subscription items.",
      "example": true
     },
     "price_type": {
      "type": "string",
      "enum": [
       "fixed",
       "free",
       "custom"
      ],
      "description": "How this line item is priced. `fixed`: a set price per cycle, the same for every customer. `free`: no charge. `custom`: the customer chose the amount at checkout, within the product's bounds.",
      "example": "fixed"
     },
     "unit_amount": {
      "type": "string",
      "description": "Price for one unit of this item, as a decimal string in the item's currency.",
      "example": "10.00"
     },
     "currency": {
      "type": "string",
      "description": "The currency this item is billed in, as an ISO 4217 code.",
      "example": "USD"
     },
     "previously_billed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "When this item was last billed, in UTC. `null` if it has not been billed yet.",
      "example": "2026-04-01T00:00:00Z"
     },
     "next_billed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "When this item will next be billed, in UTC.",
      "example": "2026-05-01T00:00:00Z"
     },
     "price": {
      "allOf": [
       {
        "$ref": "#/components/schemas/SubscriptionItemPrice"
       }
      ],
      "nullable": true
     },
     "product": {
      "allOf": [
       {
        "$ref": "#/components/schemas/SubscriptionCatalogProduct"
       }
      ],
      "nullable": true
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the item was created, in UTC.",
      "example": "2026-03-01T12:00:00Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the item was last updated, in UTC.",
      "example": "2026-04-01T00:00:00Z"
     }
    }
   },
   "SubscriptionResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "sub_1a2b3c4d5e6f",
      "description": "Unique identifier for the subscription."
     },
     "customer": {
      "$ref": "#/components/schemas/Customer",
      "description": "The customer billed on each renewal, expanded inline so you can show who is being charged without a second call."
     },
     "payment_method_id": {
      "type": "string",
      "nullable": true,
      "example": "pm_7h8i9j0k",
      "description": "The saved payment method billed on each renewal. `null` until a payment method is attached."
     },
     "status": {
      "type": "string",
      "enum": [
       "trialing",
       "active",
       "past_due",
       "unpaid",
       "canceled",
       "paused"
      ],
      "description": "Status of the subscription. Set automatically by Bachs as payments succeed or fail. `trialing`: In a free trial. No payment has been collected yet. `trial_end` marks when billing begins. `active`: Active and paid. Bachs is billing this subscription automatically each cycle. `past_due`: A cycle payment failed. Bachs is retrying the payment while access continues. `unpaid`: Payment retries have been exhausted. Access should be restricted. `canceled`: Canceled and will not renew. This is a terminal state. `paused`: Temporarily suspended. Billing is halted until the subscription resumes.",
      "example": "active"
     },
     "collection_method": {
      "type": "string",
      "example": "charge_automatically",
      "description": "How renewals are collected. `charge_automatically` bills the saved card each cycle."
     },
     "currency": {
      "type": "string",
      "example": "USD",
      "description": "The currency the subscription is billed in, as an ISO 4217 code. Subscriptions are USD only today."
     },
     "amount": {
      "type": "string",
      "description": "Recurring amount as a decimal string",
      "example": "10.00"
     },
     "billing_cycle": {
      "$ref": "#/components/schemas/SubscriptionCadence",
      "description": "How often the subscription renews, as an interval unit and a frequency, for example `month` with a frequency of `1` for monthly billing."
     },
     "quantity": {
      "type": "integer",
      "description": "Total billable quantity across the subscription's line items.",
      "example": 1
     },
     "current_period_start": {
      "type": "string",
      "format": "date-time",
      "description": "Start of the period currently being billed for, in UTC.",
      "example": "2026-04-01T00:00:00Z"
     },
     "current_period_end": {
      "type": "string",
      "format": "date-time",
      "description": "End of the period currently being billed for, in UTC. The next charge lands at this time unless the subscription is canceled first.",
      "example": "2026-05-01T00:00:00Z"
     },
     "previously_billed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "Start of the period that was last billed",
      "example": "2026-04-01T00:00:00Z"
     },
     "next_billed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "Next scheduled charge date",
      "example": "2026-05-01T00:00:00Z"
     },
     "trial_end": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "When the free trial ends and billing begins, in UTC. `null` if the subscription is not trialing.",
      "example": "2026-04-15T00:00:00Z"
     },
     "cancel_at_period_end": {
      "type": "boolean",
      "description": "When `true`, the subscription stays active until `current_period_end` and is not renewed. When `false`, it renews normally.",
      "example": false
     },
     "canceled_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "When the subscription was canceled, in UTC. `null` if it has not been canceled.",
      "example": null
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the subscription was created, in UTC.",
      "example": "2026-03-01T12:00:00Z"
     },
     "product": {
      "allOf": [
       {
        "$ref": "#/components/schemas/SubscriptionCatalogProduct"
       }
      ],
      "nullable": true,
      "description": "The catalog product this subscription bills for, or `null` when the subscription is not tied to a single product."
     },
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/SubscriptionItem"
      },
      "description": "The line items that make up the subscription. Each item ties a product and its price to a billed quantity."
     },
     "metadata": {
      "type": "object",
      "description": "Your own key-value data attached to the subscription at creation, returned unchanged.",
      "example": {
       "plan": "pro",
       "seat_count": "5"
      }
     }
    }
   },
   "SubscriptionPagination": {
    "type": "object",
    "properties": {
     "next_cursor": {
      "type": "string",
      "nullable": true,
      "description": "Cursor for the next page, or `null` on the last page.",
      "example": "cur_50"
     },
     "prev_cursor": {
      "type": "string",
      "nullable": true,
      "description": "Cursor for the previous page, or `null` on the first page.",
      "example": null
     },
     "has_more": {
      "type": "boolean",
      "description": "Whether more results exist after this page.",
      "example": true
     },
     "limit": {
      "type": "integer",
      "description": "The page size that was applied.",
      "example": 50
     },
     "offset": {
      "type": "integer",
      "description": "The offset that was applied.",
      "example": 0
     },
     "returned": {
      "type": "integer",
      "description": "The number of items returned on this page.",
      "example": 50
     },
     "total": {
      "type": "integer",
      "description": "Total number of subscriptions matching the query.",
      "example": 137
     }
    }
   },
   "SubscriptionListResponse": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/SubscriptionResponse"
      },
      "description": "The subscriptions on this page, newest first. Each entry is a [Subscription](/api-reference/subscriptions/get-subscription) with the same shape the retrieve endpoint returns."
     },
     "pagination": {
      "$ref": "#/components/schemas/SubscriptionPagination",
      "description": "Where this page sits in the full result set, so you know the applied `limit` and `offset`, how many rows matched, and whether another page exists."
     }
    }
   },
   "UpdateSubscriptionRequest": {
    "type": "object",
    "description": "A single change to a subscription. Send exactly one intent per request: change the plan (product_id), move a trial (trial_end), change the payment method (payment_method_id), or update metadata (metadata). Combining intents returns 400.",
    "properties": {
     "product_id": {
      "type": "string",
      "maxLength": 64,
      "description": "Move the subscription to this product (plan). The price is resolved from the product for the subscription's currency.",
      "example": "prod_xyz456"
     },
     "trial_end": {
      "type": "string",
      "format": "date-time",
      "description": "Future = add/extend the trial; past-or-now = end it and bill now.",
      "example": "2026-05-01T00:00:00Z"
     },
     "payment_method_id": {
      "type": "string",
      "maxLength": 64,
      "description": "Point the subscription at a different saved card. If past_due/unpaid, retries immediately. Stands alone.",
      "example": "pm_9f8e7d6c5b"
     },
     "metadata": {
      "description": "Merge key-value metadata into the subscription (up to 20 keys total). Sent keys are added or overwritten; a key sent with an empty-string value is removed; send an empty string (`\"\"`) to clear all metadata. Stands alone: it cannot be combined with a plan, trial, or payment-method change.",
      "oneOf": [
       {
        "type": "object",
        "maxProperties": 20
       },
       {
        "type": "string",
        "enum": [
         ""
        ]
       }
      ],
      "example": {
       "plan": "pro",
       "seat_count": "5"
      }
     },
     "proration_behavior": {
      "type": "string",
      "enum": [
       "invoice_now",
       "next_cycle",
       "none"
      ],
      "description": "How a plan change is settled, and only meaningful alongside `product_id`. `invoice_now`: the change is settled straight away on a new invoice, and this is the default when you omit the field. `next_cycle`: the proration is accrued and drains into the next cycle's invoice. `none`: the plan changes with no proration charged or credited.",
      "example": "invoice_now"
     }
    }
   },
   "CancelSubscriptionRequest": {
    "type": "object",
    "properties": {
     "cancel_at_period_end": {
      "type": "boolean",
      "default": false,
      "description": "true = cancel at current_period_end; false = cancel immediately.",
      "example": false
     },
     "reason": {
      "type": "string",
      "maxLength": 255,
      "nullable": true,
      "description": "An optional free-text note recording why the subscription was canceled. Max 255 characters.",
      "example": "Customer requested cancellation"
     }
    }
   },
   "Customer": {
    "type": "object",
    "properties": {
     "customer_id": {
      "type": "string",
      "example": "cust_xyz789",
      "description": "Unique identifier for the customer, prefixed with `cust_`."
     },
     "email": {
      "type": "string",
      "nullable": true,
      "description": "The customer's email address.",
      "example": "jane@example.com"
     },
     "name": {
      "type": "string",
      "nullable": true,
      "description": "The customer's full name. `null` when not set.",
      "example": "Jane Doe"
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "description": "The customer's phone number in E.164 format, e.g. `+2348012345678`.",
      "example": "+2348012345678"
     },
     "metadata": {
      "type": "object",
      "description": "Your own key-value data attached to the customer.",
      "example": {
       "plan": "pro"
      }
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when the customer was created.",
      "example": "2026-01-24T12:00:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when the customer was last updated.",
      "example": "2026-01-24T12:00:00.000Z"
     },
     "billing_address": {
      "allOf": [
       {
        "$ref": "#/components/schemas/CustomerBillingAddress"
       }
      ],
      "nullable": true,
      "description": "The customer's billing address, or `null` if none is set."
     }
    }
   },
   "PaymentResponse": {
    "type": "object",
    "description": "Detailed payment response for API integrations.",
    "properties": {
     "reference": {
      "type": "string",
      "nullable": true,
      "description": "Checkout reference when available.",
      "example": "order_9876"
     },
     "payment_id": {
      "type": "string",
      "description": "Unique identifier for the payment.",
      "example": "pay_1a2b3c4d5e"
     },
     "billing_reason": {
      "type": "string",
      "enum": [
       "purchase",
       "subscription_create",
       "subscription_cycle",
       "subscription_update"
      ],
      "description": "Why this payment exists. `purchase`: a one-time purchase. `subscription_create`: the first cycle of a new subscription. `subscription_cycle`: a subscription renewal. `subscription_update`: an off-cycle charge from a mid-cycle plan change (proration).",
      "example": "purchase"
     },
     "checkout_id": {
      "type": "string",
      "nullable": true,
      "description": "Checkout identifier, when linked.",
      "example": "chk_8T9u0V1w2X3y4Z5a"
     },
     "status": {
      "type": "string",
      "description": "Current status of the payment. `created`: the charge exists and no attempt has succeeded yet. `processing`: an attempt is in flight and is being verified. `succeeded`: the payment is confirmed and settled in full. `accepted`: an underpayment or overpayment was accepted as final settlement. `failed`: the payment failed and no funds were captured. `expired`: the payment window elapsed before any payment arrived. `cancelled`: cancelled before completion. `refunded`: the full amount was returned to the customer. `partially_refunded`: part of the amount was returned to the customer. `auto_refunded`: we automatically returned the full amount to the customer. `underpaid`: the customer paid less than the amount owed. `overpaid`: the customer paid more than the amount owed.",
      "enum": [
       "created",
       "processing",
       "succeeded",
       "accepted",
       "failed",
       "expired",
       "cancelled",
       "refunded",
       "partially_refunded",
       "auto_refunded",
       "underpaid",
       "overpaid"
      ],
      "x-enum-descriptions": {
       "created": "Charge created and awaiting payment.",
       "processing": "Payment received and being verified.",
       "succeeded": "Payment confirmed and fully settled.",
       "accepted": "Payment accepted by the processor, pending final confirmation.",
       "failed": "Payment failed; no funds captured.",
       "expired": "Charge expired before payment was received.",
       "cancelled": "Charge cancelled before completion.",
       "refunded": "Full refund issued.",
       "partially_refunded": "Partial refund issued.",
       "auto_refunded": "Full refund issued automatically.",
       "underpaid": "Payment received was less than the requested amount.",
       "overpaid": "Payment received exceeded the requested amount."
      },
      "example": "succeeded"
     },
     "is_refundable": {
      "type": "boolean",
      "nullable": true,
      "description": "Whether this payment can currently be refunded.",
      "example": true
     },
     "amount": {
      "type": "string",
      "description": "Requested amount in `currency`.",
      "example": "10.00"
     },
     "amount_paid": {
      "type": "string",
      "nullable": true,
      "description": "Amount received so far.",
      "example": "10.00"
     },
     "amount_remaining": {
      "type": "string",
      "nullable": true,
      "description": "Remaining amount still expected.",
      "example": "0.00"
     },
     "currency": {
      "type": "string",
      "description": "Payment currency code.",
      "example": "USD"
     },
     "fee_usd": {
      "type": "string",
      "description": "Processing fee for this payment, converted to USD and expressed as a decimal string. `null` until the payment settles.",
      "example": "0.59",
      "nullable": true
     },
     "fees": {
      "allOf": [
       {
        "$ref": "#/components/schemas/FeeInfo"
       }
      ],
      "nullable": true,
      "description": "The processing fee on this payment, in the currency it was charged in. Prefer this over `fee_usd` when the payment was not collected in USD: `fee_usd` is a conversion of the same fee, this is the amount actually taken. `null` on a payment that carries no processing fee. See [Fees](/for-you/fees)."
     },
     "merchant_bears_cost": {
      "type": "boolean",
      "nullable": true,
      "description": "Whether merchant bears processing cost.",
      "example": true
     },
     "platform_fee": {
      "type": "string",
      "nullable": true,
      "description": "What the platform took out of this sale, beside the gross it was taken from, in the base currency of the sale. `null` when the charge carried no platform fee, and on a charge that split the sale with `transfer_data.amount` instead. See [Platform fees](/connect/platform-fees).",
      "example": null
     },
     "destination_amount": {
      "type": "string",
      "nullable": true,
      "description": "The seller's contracted share of this sale, in the base currency of the sale. Null on a charge that carries no split, and on one that split the sale with `platform_fee` instead.",
      "example": null
     },
     "fee_paid_by": {
      "type": "string",
      "nullable": true,
      "enum": [
       "merchant",
       "platform"
      ],
      "description": "Who Bachs's processing fee actually came from on this charge, read back from the ledger posting rather than a flag decided in advance. `merchant`: the fee came out of the charge. `platform`: the platform's own balance covered it. On a destination charge this never reads `platform`; the fee always comes from the charge there. See [Processing fees](/connect/processing-fees).",
      "example": "merchant"
     },
     "payment_method": {
      "type": "string",
      "nullable": true,
      "description": "Payment method used for this payment. For every method except card, this is the exact corridor collected, such as `NGN_BANK_TRANSFER`, `MOMO_GHS`, or `CRYPTO`. Card charges report `CARD` rather than `USD_CARD` or `NGN_CARD`; read the currency to tell which card corridor collected it.",
      "example": "NGN_BANK_TRANSFER"
     },
     "channel": {
      "type": "string",
      "nullable": true,
      "description": "Origin channel (for example `api`).",
      "example": "checkout"
     },
     "narration": {
      "type": "string",
      "nullable": true,
      "description": "payment description/narration.",
      "example": "Pro plan"
     },
     "meta": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Public metadata stored for this payment.",
      "example": {
       "order_id": "ORD-9876"
      }
     },
     "message": {
      "type": "string",
      "nullable": true,
      "description": "Human-readable payment message derived from status.",
      "example": "Successful"
     },
     "customer": {
      "type": "object",
      "nullable": true,
      "description": "Customer information when available.",
      "properties": {
       "name": {
        "type": "string",
        "nullable": true,
        "description": "Full name of the customer associated with this payment, when captured."
       },
       "email": {
        "type": "string",
        "nullable": true,
        "description": "Customer email address associated with this payment, when captured."
       }
      }
     },
     "line_items": {
      "type": "array",
      "nullable": true,
      "description": "The line items this payment covers.",
      "items": {
       "$ref": "#/components/schemas/PaymentProductItem"
      }
     },
     "subscription_id": {
      "type": "string",
      "nullable": true,
      "description": "The subscription this payment belongs to, or `null` for a one-time purchase.",
      "example": null
     },
     "invoice": {
      "allOf": [
       {
        "$ref": "#/components/schemas/PaymentInvoiceInfo"
       }
      ],
      "nullable": true,
      "description": "The invoice this payment collected. Present only for subscription payments; `null` for one-time purchases."
     },
     "refunds": {
      "type": "array",
      "nullable": true,
      "description": "IDs of any refunds issued for this payment. `null` if no refund has been created.",
      "items": {
       "type": "string"
      },
      "example": [
       "ref_1a2b3c4d5e"
      ]
     },
     "status_history": {
      "type": "array",
      "nullable": true,
      "description": "Chronological list of status changes for this payment.",
      "items": {
       "type": "object",
       "properties": {
        "status": {
         "type": "string",
         "description": "Status at this point in time.",
         "example": "succeeded"
        },
        "occurred_at": {
         "type": "string",
         "format": "date-time",
         "description": "When this status change occurred.",
         "example": "2026-01-24T14:35:00.000Z"
        },
        "reason": {
         "type": "string",
         "nullable": true,
         "description": "Human-readable reason for the status change, if available."
        }
       }
      }
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "Creation timestamp.",
      "example": "2026-04-27T12:00:00Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "Last update timestamp.",
      "example": "2026-04-27T12:00:05Z"
     },
     "completed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "Completion timestamp when available.",
      "example": "2026-04-27T12:00:05Z"
     }
    },
    "required": [
     "payment_id",
     "status",
     "amount",
     "currency",
     "created_at",
     "updated_at"
    ]
   },
   "PaymentListResponse": {
    "type": "object",
    "description": "A paginated list of payments.",
    "properties": {
     "items": {
      "type": "array",
      "description": "Payments for the current page.",
      "items": {
       "$ref": "#/components/schemas/PaymentListItemResponse"
      }
     },
     "pagination": {
      "$ref": "#/components/schemas/PaymentPagination"
     }
    },
    "required": [
     "items",
     "pagination"
    ]
   },
   "PaymentListItemResponse": {
    "type": "object",
    "description": "Paginated list representation of a payment record.",
    "properties": {
     "reference": {
      "type": "string",
      "nullable": true,
      "description": "Checkout reference for this payment when available.",
      "example": "order_9876"
     },
     "id": {
      "type": "string",
      "nullable": true,
      "description": "payment ID for retrieval and reconciliation.",
      "example": "chrg_1a2b3c4d5e"
     },
     "status": {
      "type": "string",
      "description": "Current payment status for this payment.",
      "example": "succeeded"
     },
     "is_refundable": {
      "type": "boolean",
      "nullable": true,
      "description": "Whether this payment is currently eligible for refund operations.",
      "example": true
     },
     "amount": {
      "type": "string",
      "description": "Requested payment amount in `currency`.",
      "example": "10.00"
     },
     "customer_name": {
      "type": "string",
      "description": "Customer full name from checkout data. May be empty when unavailable.",
      "example": "Jane Doe"
     },
     "customer_email": {
      "type": "string",
      "description": "Customer email from checkout data. May be empty when unavailable.",
      "example": "customer@example.com"
     },
     "amount_paid": {
      "type": "string",
      "nullable": true,
      "description": "Amount received so far for this payment.",
      "example": "10.00"
     },
     "amount_remaining": {
      "type": "string",
      "nullable": true,
      "description": "Remaining amount expected before full completion.",
      "example": "0.00"
     },
     "settlement_amount": {
      "type": "string",
      "nullable": true,
      "description": "Settlement-side amount captured for this payment.",
      "example": "10.00"
     },
     "settlement_currency": {
      "type": "string",
      "nullable": true,
      "description": "Settlement currency code for `settlement_amount`.",
      "example": "USD"
     },
     "fee": {
      "type": "string",
      "nullable": true,
      "description": "The Bachs processing fee on this payment, as a decimal string in the item's `currency`. The same figure the retrieve endpoint returns as `fees.amount`, without the currency beside it. `null` on a payment that carries no processing fee. See [Fees](/for-you/fees).",
      "example": "0.90"
     },
     "vat": {
      "type": "string",
      "nullable": true,
      "description": "Reserved VAT field in list responses. May be null.",
      "example": null
     },
     "currency": {
      "type": "string",
      "description": "Payment currency code.",
      "example": "USD"
     },
     "meta": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Public metadata attached to the payment when available.",
      "example": null
     },
     "transaction_date": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when the payment was created.",
      "example": "2026-04-27T12:00:00Z"
     },
     "completed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when the payment reached a successful terminal state.",
      "example": "2026-04-27T12:00:05Z"
     },
     "platform_fee": {
      "type": "string",
      "nullable": true,
      "description": "On a destination charge stated fee-first, the platform's cut of this sale, as a decimal string in `currency`. Null on every other payment, including one whose split was stated share-first.",
      "example": "20.00"
     },
     "destination_amount": {
      "type": "string",
      "nullable": true,
      "description": "On a destination charge stated share-first, the amount the connected account receives, as a decimal string. Null on every other payment, including one whose split was stated fee-first.",
      "example": "80.00"
     },
     "fee_paid_by": {
      "type": "string",
      "nullable": true,
      "enum": [
       "merchant",
       "platform"
      ],
      "description": "Who Bachs's processing fee came from on this charge. `merchant` means it came out of the charge itself. `platform` means the platform's own balance covered it. Null until the charge settles, because the outcome is not decided before then.",
      "example": "merchant"
     }
    },
    "required": [
     "status",
     "amount",
     "customer_name",
     "customer_email",
     "currency"
    ]
   },
   "PaymentPagination": {
    "type": "object",
    "description": "Pagination details for a payments list.",
    "properties": {
     "next_cursor": {
      "type": "string",
      "description": "Cursor for the next page, or `null` on the last page.",
      "example": "cur_50",
      "nullable": true
     },
     "prev_cursor": {
      "type": "string",
      "description": "Cursor for the previous page, or `null` on the first page.",
      "example": null,
      "nullable": true
     },
     "has_more": {
      "type": "boolean",
      "description": "Whether more results exist after this page.",
      "example": true
     },
     "limit": {
      "type": "integer",
      "description": "The page size that was applied.",
      "example": 50
     },
     "offset": {
      "type": "integer",
      "description": "The offset that was applied.",
      "example": 0
     },
     "returned": {
      "type": "integer",
      "description": "Number of items returned on this page.",
      "example": 50
     },
     "total": {
      "type": "integer",
      "description": "Total number of payments matching the query.",
      "example": 150
     }
    },
    "required": [
     "has_more",
     "limit",
     "offset",
     "returned",
     "total"
    ]
   },
   "PaymentInvoiceInfo": {
    "type": "object",
    "description": "A subscription invoice this payment collected.",
    "properties": {
     "invoice_id": {
      "type": "string",
      "description": "The invoice's identifier.",
      "example": "inv_9a8b7c6d5e"
     },
     "number": {
      "type": "string",
      "nullable": true,
      "description": "Human-facing invoice number, if assigned.",
      "example": "inv_9a8b7c6d5e"
     },
     "subscription_id": {
      "type": "string",
      "nullable": true,
      "description": "The subscription the invoice belongs to.",
      "example": "sub_1a2b3c4d5e"
     },
     "period_start": {
      "type": "string",
      "format": "date-time",
      "description": "Start of the billing period, UTC.",
      "example": "2026-04-01T00:00:00Z"
     },
     "period_end": {
      "type": "string",
      "format": "date-time",
      "description": "End of the billing period, UTC.",
      "example": "2026-05-01T00:00:00Z"
     },
     "kind": {
      "type": "string",
      "enum": [
       "cycle",
       "proration"
      ],
      "description": "`cycle`: a regular subscription-period invoice. `proration`: an off-cycle mid-cycle change.",
      "example": "cycle"
     }
    },
    "required": [
     "invoice_id"
    ]
   },
   "CheckoutCustomer": {
    "type": "object",
    "description": "The customer attached to the checkout.",
    "properties": {
     "id": {
      "type": "string",
      "description": "The customer's ID, once resolved. `null` until a customer is matched or created.",
      "example": "cust_1a2b3c4d5e6f",
      "nullable": true
     },
     "email": {
      "type": "string",
      "description": "The customer's email address. `null` until the buyer supplies it on the hosted page, on a checkout created without a `customer`.",
      "example": "jane@example.com",
      "nullable": true
     },
     "name": {
      "type": "string",
      "description": "The customer's name. `null` when not provided.",
      "example": "Jane Doe",
      "nullable": true
     }
    }
   },
   "CheckoutCustomerDetails": {
    "type": "object",
    "description": "What the buyer supplied, whether or not a customer record exists for them. Present whenever an identity was collected, `null` before then. Use it when you want the buyer's email and name and do not need an id you can pass back to the customers API. See [`customer` vs `customer_details`](/api-reference/checkout-sessions/object#customer-vs-customer-details).",
    "properties": {
     "email": {
      "type": "string",
      "description": "The email the buyer supplied.",
      "example": "jane@example.com",
      "nullable": true
     },
     "name": {
      "type": "string",
      "description": "The name the buyer supplied. `null` when not given.",
      "example": "Jane Doe",
      "nullable": true
     }
    }
   },
   "CheckoutRecurring": {
    "type": "object",
    "description": "The recurring cadence when the checkout starts a subscription. `null` for a one-time checkout.",
    "properties": {
     "interval": {
      "type": "string",
      "description": "The billing interval.",
      "enum": [
       "day",
       "week",
       "month",
       "year"
      ],
      "example": "month"
     },
     "interval_count": {
      "type": "integer",
      "description": "Number of intervals per billing cycle.",
      "example": 1,
      "default": 1
     }
    },
    "required": [
     "interval"
    ]
   },
   "WebhookEndpoint": {
    "type": "object",
    "description": "A webhook endpoint: a URL Bachs delivers events to, and the events it is subscribed to.",
    "properties": {
     "endpoint_id": {
      "type": "string",
      "description": "Use this identifier to fetch, update, delete, or rotate the secret on this endpoint, and to scope event listings to it.",
      "example": "whe_a1e823c073ab743ce5969ceef2db4d42"
     },
     "name": {
      "type": "string",
      "description": "The label you gave the endpoint. It is never sent to the endpoint itself.",
      "example": "Production events"
     },
     "url": {
      "type": "string",
      "description": "The HTTPS URL we POST each subscribed event to. It must be reachable from the public internet and should return a 2xx quickly, since a slow or non-2xx response is recorded as a failed attempt and retried.",
      "format": "uri",
      "example": "https://api.example.com/webhooks/bachs"
     },
     "enabled": {
      "type": "boolean",
      "description": "When `true`, matching events are delivered here. When `false`, events still occur on your account but nothing is sent to this URL.",
      "example": true
     },
     "event_types": {
      "type": "array",
      "description": "The event types this endpoint receives, stored lowercase. Anything not listed is never delivered here, so add a type before you rely on it.",
      "items": {
       "type": "string",
       "enum": [
        "collection.succeeded",
        "collection.failed",
        "collection.underpaid",
        "checkout.completed",
        "checkout.expired",
        "payout.created",
        "payout.paid",
        "payout.failed",
        "refund.created",
        "refund.paid",
        "refund.failed",
        "conversion.completed",
        "conversion.failed",
        "customer.created",
        "customer.updated",
        "dispute.created",
        "dispute.updated",
        "customer.subscription.created",
        "customer.subscription.updated",
        "customer.subscription.deleted",
        "invoice.created",
        "invoice.paid",
        "invoice.payment_failed"
       ]
      },
      "example": [
       "collection.succeeded",
       "collection.failed"
      ]
     },
     "created_at": {
      "type": "string",
      "description": "When the endpoint was created, as an ISO 8601 timestamp in UTC.",
      "example": "2026-03-09T10:00:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "description": "When the endpoint was last changed, as an ISO 8601 timestamp in UTC. Rotating the signing secret updates this.",
      "example": "2026-03-09T10:00:00.000Z"
     },
     "event_source": {
      "type": "string",
      "enum": [
       "account",
       "connect",
       "all"
      ],
      "description": "Which account's events reach this endpoint. `account`: only events that happened on your own account. `connect`: only events that happened on accounts you own. `all`: both.",
      "example": "account"
     }
    },
    "required": [
     "endpoint_id",
     "name",
     "url",
     "enabled",
     "event_types",
     "created_at",
     "updated_at"
    ]
   },
   "CreateWebhookEndpointRequest": {
    "type": "object",
    "description": "Parameters for creating a webhook endpoint.",
    "properties": {
     "name": {
      "type": "string",
      "description": "A label you choose to tell this endpoint apart from your others in the dashboard and in list responses. It is never sent to the endpoint.",
      "example": "Production events"
     },
     "url": {
      "type": "string",
      "description": "The HTTPS URL we POST each subscribed event to. It must be reachable from the public internet and should return a 2xx quickly, since a slow or non-2xx response is recorded as a failed attempt and retried.",
      "format": "uri",
      "example": "https://api.example.com/webhooks/bachs"
     },
     "event_types": {
      "type": "array",
      "minItems": 1,
      "description": "The event types this endpoint receives. Send at least one; anything not listed is never delivered here, so add a type before you rely on it. Values are matched case-insensitively and stored lowercase.",
      "items": {
       "type": "string",
       "enum": [
        "collection.succeeded",
        "collection.failed",
        "collection.underpaid",
        "checkout.completed",
        "checkout.expired",
        "payout.created",
        "payout.paid",
        "payout.failed",
        "refund.created",
        "refund.paid",
        "refund.failed",
        "conversion.completed",
        "conversion.failed",
        "customer.created",
        "customer.updated",
        "dispute.created",
        "dispute.updated",
        "customer.subscription.created",
        "customer.subscription.updated",
        "customer.subscription.deleted",
        "invoice.created",
        "invoice.paid",
        "invoice.payment_failed"
       ]
      },
      "example": [
       "collection.succeeded",
       "collection.failed"
      ]
     },
     "event_source": {
      "type": "string",
      "enum": [
       "account",
       "connect",
       "all"
      ],
      "description": "Which account's events reach this endpoint. `account`: only events that happened on your own account. `connect`: only events that happened on accounts you own. `all`: both. Defaults to `account` when you omit it.",
      "example": "account"
     }
    },
    "required": [
     "name",
     "url",
     "event_types"
    ]
   },
   "UpdateWebhookEndpointRequest": {
    "type": "object",
    "description": "Fields to update on a webhook endpoint. Only the fields you send are changed.",
    "properties": {
     "name": {
      "type": "string",
      "description": "Replaces the endpoint's label. Omit it to leave the current label unchanged.",
      "example": "Production events (v2 receiver)",
      "nullable": true
     },
     "url": {
      "type": "string",
      "description": "Moves delivery to a different HTTPS URL. Events already queued for the old URL are retried against the new one, so cut over only once the new receiver is live.",
      "format": "uri",
      "example": "https://api.example.com/webhooks/bachs/v2",
      "nullable": true
     },
     "event_types": {
      "type": "array",
      "nullable": true,
      "description": "Replaces the whole subscription list rather than adding to it, so send every type you still want. Omit the field to leave the current list untouched; sending an empty array is rejected.",
      "items": {
       "type": "string",
       "enum": [
        "collection.succeeded",
        "collection.failed",
        "collection.underpaid",
        "checkout.completed",
        "checkout.expired",
        "payout.created",
        "payout.paid",
        "payout.failed",
        "refund.created",
        "refund.paid",
        "refund.failed",
        "conversion.completed",
        "conversion.failed",
        "customer.created",
        "customer.updated",
        "dispute.created",
        "dispute.updated",
        "customer.subscription.created",
        "customer.subscription.updated",
        "customer.subscription.deleted",
        "invoice.created",
        "invoice.paid",
        "invoice.payment_failed"
       ]
      },
      "example": [
       "collection.succeeded"
      ]
     },
     "event_source": {
      "type": "string",
      "enum": [
       "account",
       "connect",
       "all"
      ],
      "description": "Changes which account's events reach this endpoint. `account`: only your own account's events. `connect`: only the events of accounts you own. `all`: both. Omit it to leave the current setting unchanged.",
      "example": "all"
     }
    }
   },
   "CreateWebhookEndpointResponse": {
    "type": "object",
    "description": "The created endpoint, plus its signing secret. The secret is returned only once, on creation. Store it securely.",
    "properties": {
     "endpoint_id": {
      "type": "string",
      "description": "Use this identifier to fetch, update, delete, or rotate the secret on this endpoint, and to scope event listings to it.",
      "example": "whe_a1e823c073ab743ce5969ceef2db4d42"
     },
     "name": {
      "type": "string",
      "description": "The label you gave the endpoint. It is never sent to the endpoint itself.",
      "example": "Production events"
     },
     "url": {
      "type": "string",
      "description": "The HTTPS URL we POST each subscribed event to.",
      "format": "uri",
      "example": "https://api.example.com/webhooks/bachs"
     },
     "enabled": {
      "type": "boolean",
      "description": "When `true`, matching events are delivered here. A new endpoint is enabled straight away, so have your receiver deployed before you create it.",
      "example": true
     },
     "event_types": {
      "type": "array",
      "description": "The event types this endpoint now receives, stored lowercase. Anything not listed is never delivered here.",
      "items": {
       "type": "string",
       "enum": [
        "collection.succeeded",
        "collection.failed",
        "collection.underpaid",
        "checkout.completed",
        "checkout.expired",
        "payout.created",
        "payout.paid",
        "payout.failed",
        "refund.created",
        "refund.paid",
        "refund.failed",
        "conversion.completed",
        "conversion.failed",
        "customer.created",
        "customer.updated",
        "dispute.created",
        "dispute.updated",
        "customer.subscription.created",
        "customer.subscription.updated",
        "customer.subscription.deleted",
        "invoice.created",
        "invoice.paid",
        "invoice.payment_failed"
       ]
      },
      "example": [
       "collection.succeeded",
       "collection.failed"
      ]
     },
     "created_at": {
      "type": "string",
      "description": "When the endpoint was created, as an ISO 8601 timestamp in UTC.",
      "example": "2026-03-09T10:00:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "description": "When the endpoint was last changed, as an ISO 8601 timestamp in UTC. Rotating the signing secret updates this.",
      "example": "2026-03-09T10:00:00.000Z"
     },
     "signing_secret": {
      "type": "string",
      "description": "Use this to verify the `X-Bachs-Signature` header on every delivery to this endpoint and reject anything that does not match. It is shown in full only in this response, so store it in your secret manager now; afterwards you can only read it back from [Get Endpoint Secret](/api-reference/webhooks/get-webhook-endpoint-secret) or replace it by rotating.",
      "example": "whsec_62da9edb5b97b120f7d55e1e190118b0ec08fcace294dfaf211ec370b6d21f34"
     },
     "event_source": {
      "type": "string",
      "enum": [
       "account",
       "connect",
       "all"
      ],
      "description": "Which account's events reach this endpoint. `account`: only your own account's events. `connect`: only the events of accounts you own. `all`: both.",
      "example": "account"
     }
    },
    "required": [
     "endpoint_id",
     "name",
     "url",
     "enabled",
     "event_types",
     "created_at",
     "updated_at",
     "signing_secret"
    ]
   },
   "WebhookEndpointSecretResponse": {
    "type": "object",
    "description": "An endpoint with its current signing secret.",
    "properties": {
     "endpoint_id": {
      "type": "string",
      "description": "Use this identifier to fetch, update, delete, or rotate the secret on this endpoint, and to scope event listings to it.",
      "example": "whe_a1e823c073ab743ce5969ceef2db4d42"
     },
     "name": {
      "type": "string",
      "description": "The label you gave the endpoint. It is never sent to the endpoint itself.",
      "example": "Production events"
     },
     "url": {
      "type": "string",
      "description": "The HTTPS URL we POST each subscribed event to.",
      "format": "uri",
      "example": "https://api.example.com/webhooks/bachs"
     },
     "enabled": {
      "type": "boolean",
      "description": "When `true`, matching events are delivered here. When `false`, events still occur on your account but nothing is sent to this URL.",
      "example": true
     },
     "event_types": {
      "type": "array",
      "description": "The event types this endpoint receives, stored lowercase. Anything not listed is never delivered here.",
      "items": {
       "type": "string",
       "enum": [
        "collection.succeeded",
        "collection.failed",
        "collection.underpaid",
        "checkout.completed",
        "checkout.expired",
        "payout.created",
        "payout.paid",
        "payout.failed",
        "refund.created",
        "refund.paid",
        "refund.failed",
        "conversion.completed",
        "conversion.failed",
        "customer.created",
        "customer.updated",
        "dispute.created",
        "dispute.updated",
        "customer.subscription.created",
        "customer.subscription.updated",
        "customer.subscription.deleted",
        "invoice.created",
        "invoice.paid",
        "invoice.payment_failed"
       ]
      },
      "example": [
       "collection.succeeded",
       "collection.failed"
      ]
     },
     "created_at": {
      "type": "string",
      "description": "When the endpoint was created, as an ISO 8601 timestamp in UTC.",
      "example": "2026-03-09T10:00:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "description": "When the endpoint was last changed, as an ISO 8601 timestamp in UTC. Rotating the signing secret updates this.",
      "example": "2026-03-09T10:00:00.000Z"
     },
     "secret": {
      "type": "string",
      "description": "Use this to verify the `X-Bachs-Signature` header on every delivery to this endpoint and reject anything that does not match. This response and the create response are the only places it is shown in full, so treat it like a password: never log it, never put it in client-side code, and rotate it if it leaks.",
      "example": "whsec_62da9edb5b97b120f7d55e1e190118b0ec08fcace294dfaf211ec370b6d21f34"
     },
     "event_source": {
      "type": "string",
      "enum": [
       "account",
       "connect",
       "all"
      ],
      "description": "Which account's events reach this endpoint. `account`: only your own account's events. `connect`: only the events of accounts you own. `all`: both.",
      "example": "account"
     }
    },
    "required": [
     "endpoint_id",
     "secret"
    ]
   },
   "WebhookMetricsDataPoint": {
    "type": "object",
    "description": "Delivery counts for one period.",
    "properties": {
     "date": {
      "type": "string",
      "description": "The first day of the bucket, as a `YYYY-MM-DD` date in UTC. For `week` and `month` periods this is the day the bucket starts, not a range.",
      "example": "2026-03-09"
     },
     "success": {
      "type": "integer",
      "description": "How many attempts in this bucket got a 2xx from your endpoint. A retry that eventually succeeds counts here as well as counting its earlier failures in `failed`.",
      "example": 24
     },
     "failed": {
      "type": "integer",
      "description": "How many attempts in this bucket got a non-2xx response or never connected. A sustained non-zero value means your receiver is rejecting or timing out and events are being retried.",
      "example": 1
     }
    }
   },
   "WebhookMetricsResponse": {
    "type": "object",
    "description": "Delivery metrics for an endpoint over a time range.",
    "properties": {
     "total": {
      "type": "string",
      "description": "The number of delivery attempts across the whole range, as a string. It equals the sum of `success` and `failed` over every entry in `data`, so use it to compute a success rate without re-adding the series.",
      "example": "160"
     },
     "period": {
      "type": "string",
      "description": "How the series is bucketed. `day`: one entry per calendar day (the default, over the last 30 days when you send no dates). `week`: one entry per week. `month`: one entry per month. An unrecognised value falls back to `day`.",
      "example": "day"
     },
     "data": {
      "type": "array",
      "description": "One entry per bucket in the range, in ascending time order. Buckets with no attempts are still returned with zero counts, so the series is safe to plot without filling gaps yourself.",
      "items": {
       "$ref": "#/components/schemas/WebhookMetricsDataPoint"
      }
     }
    },
    "required": [
     "total",
     "period",
     "data"
    ]
   },
   "WebhookEventListItem": {
    "type": "object",
    "description": "A summary of a webhook event across all endpoints.",
    "properties": {
     "event_id": {
      "type": "string",
      "description": "Pass this to [Get Event](/api-reference/webhooks/get-webhook-event) for the full payload and attempt history. It is also the `id` inside the delivered payload, so you can use it to deduplicate on your side.",
      "example": "evt_5d50b401e3e47948235c374ae57b8807"
     },
     "event_type": {
      "type": "string",
      "description": "What happened, in `resource.action` form, for example `customer.created` or `payout.paid`. Branch on this before reading the payload.",
      "example": "customer.created"
     },
     "entity_type": {
      "type": "string",
      "description": "The kind of resource the event is about, for example `customer`, `charge`, `payout`, `refund`, or `checkout`. It is `null` when the event carries no identifiable resource.",
      "example": "customer",
      "nullable": true
     },
     "entity_id": {
      "type": "string",
      "description": "The identifier of the resource named by `entity_type`, so you can correlate the event with your own records without opening the payload. It is `null` when the event carries no identifiable resource.",
      "example": "cust_9ae63038729d2d6b793423bdbc27c19a",
      "nullable": true
     },
     "created_at": {
      "type": "string",
      "description": "When the event was recorded, as an ISO 8601 timestamp in UTC. Events are returned newest first by this value, not by when they were delivered.",
      "example": "2026-03-09T10:00:00.000Z"
     },
     "attempts": {
      "type": "integer",
      "description": "How many delivery attempts your endpoints have made for this event in total. It is `0` when no endpoint was subscribed to this event type at the time.",
      "example": 2
     },
     "success": {
      "type": "integer",
      "description": "How many of those attempts were answered with a 2xx. Anything above zero means you have received this event at least once and should have handled it idempotently.",
      "example": 1
     },
     "failed": {
      "type": "integer",
      "description": "How many of those attempts were rejected or never connected. A non-zero value with `success` at zero means this event has not reached you yet.",
      "example": 1
     },
     "last_attempt_at": {
      "type": "string",
      "description": "When the most recent attempt was made, as an ISO 8601 timestamp in UTC. It is `null` when the event has never been attempted.",
      "example": "2026-03-09T10:02:41.000Z",
      "nullable": true
     },
     "last_attempt_status": {
      "type": "string",
      "nullable": true,
      "enum": [
       "pending",
       "succeeded",
       "failed"
      ],
      "description": "How the most recent attempt ended. `pending`: queued and not yet sent. `succeeded`: your endpoint answered with a 2xx. `failed`: your endpoint answered with a non-2xx or could not be reached. It is `null` when the event has never been attempted.",
      "example": "succeeded"
     },
     "last_attempt_http_status": {
      "type": "integer",
      "nullable": true,
      "description": "The HTTP status code your endpoint returned on the most recent attempt. It is `null` when the connection never completed, for example on a DNS failure or a timeout, which is what distinguishes a transport failure from a rejection.",
      "example": 200
     },
     "last_attempt_error": {
      "type": "string",
      "nullable": true,
      "description": "Why the most recent attempt failed, as a short diagnostic string you can act on, for example a timeout or a TLS failure. It is `null` when the attempt succeeded or none has been made.",
      "example": null
     },
     "account": {
      "type": "string",
      "nullable": true,
      "description": "The account the event happened on. It is your own account for your own activity, and the id of the account when the event came from one of the accounts you own, so use it to route the event to the right tenant.",
      "example": "acct_MxIFSNnNbZ1N4jaP"
     }
    },
    "required": [
     "event_id",
     "event_type",
     "created_at",
     "attempts",
     "success",
     "failed"
    ]
   },
   "WebhookEventsListResponse": {
    "type": "object",
    "description": "A paginated list of webhook events.",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/WebhookEventListItem"
      },
      "description": "Your account's events plus those of any accounts you own, newest first, whether or not they were ever delivered. Each entry is a summary; fetch the full payload and attempt history with [Get Event](/api-reference/webhooks/get-webhook-event)."
     },
     "total": {
      "type": "integer",
      "description": "How many events exist across your account and the accounts you own, ignoring `limit` and `offset`. Use it to decide whether another page is worth requesting.",
      "example": 2
     },
     "limit": {
      "type": "integer",
      "description": "The page size actually applied, which is clamped to between 1 and 100 whatever you request.",
      "example": 50
     },
     "offset": {
      "type": "integer",
      "description": "How many events were skipped before this page. Add `limit` to it to request the next page.",
      "example": 0
     }
    },
    "required": [
     "items",
     "total",
     "limit",
     "offset"
    ]
   },
   "WebhookEndpointEventListItem": {
    "type": "object",
    "description": "A summary of an event's delivery to one endpoint.",
    "properties": {
     "event_id": {
      "type": "string",
      "description": "Pass this to [Get Endpoint Event](/api-reference/webhooks/get-webhook-endpoint-event) for the full payload and attempt history, or to the resend endpoint to try delivery again.",
      "example": "evt_5d50b401e3e47948235c374ae57b8807"
     },
     "event_type": {
      "type": "string",
      "description": "What happened, in `resource.action` form, for example `customer.created` or `payout.paid`. Branch on this before reading the payload.",
      "example": "customer.created"
     },
     "entity_id": {
      "type": "string",
      "description": "The identifier of the resource the event is about, so you can correlate the event with your own records without opening the payload. It is `null` when the event carries no identifiable resource.",
      "example": "cust_9ae63038729d2d6b793423bdbc27c19a",
      "nullable": true
     },
     "attempts": {
      "type": "integer",
      "description": "How many times we have tried to deliver this event to this endpoint, including the original send and every retry.",
      "example": 2
     },
     "success": {
      "type": "integer",
      "description": "How many of those attempts your endpoint answered with a 2xx. Anything above zero means you have received this event at least once and should have handled it idempotently.",
      "example": 1
     },
     "failed": {
      "type": "integer",
      "description": "How many of those attempts were rejected or never connected. A non-zero value with `success` at zero means this event has not reached you yet.",
      "example": 1
     },
     "last_attempt_status": {
      "type": "string",
      "description": "How the most recent attempt ended. `pending`: queued and not yet sent. `succeeded`: your endpoint answered with a 2xx. `failed`: your endpoint answered with a non-2xx or could not be reached. It is `null` when no attempt has been recorded yet.",
      "example": "succeeded",
      "nullable": true
     },
     "last_attempt_http_status": {
      "type": "integer",
      "description": "The HTTP status code your endpoint returned on the most recent attempt. It is `null` when the connection never completed, for example on a DNS failure or a timeout, which is what distinguishes a transport failure from a rejection.",
      "example": 200,
      "nullable": true
     },
     "last_attempt_at": {
      "type": "string",
      "description": "When the most recent attempt was made, as an ISO 8601 timestamp in UTC. It is `null` when no attempt has been recorded yet.",
      "example": "2026-03-09T10:02:41.000Z",
      "nullable": true
     },
     "last_attempt_error": {
      "type": "string",
      "nullable": true,
      "description": "Why the most recent attempt failed, as a short diagnostic string you can act on, for example a timeout or a TLS failure. It is `null` when the attempt succeeded.",
      "example": null
     }
    },
    "required": [
     "event_id",
     "event_type",
     "attempts",
     "success",
     "failed"
    ]
   },
   "WebhookEndpointEventsListResponse": {
    "type": "object",
    "description": "A paginated list of events delivered to an endpoint.",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/WebhookEndpointEventListItem"
      },
      "description": "The events this endpoint has been sent, newest attempt first. Each entry summarises delivery to this one endpoint; fetch the full payload and every attempt with [Get Endpoint Event](/api-reference/webhooks/get-webhook-endpoint-event)."
     },
     "total": {
      "type": "integer",
      "description": "How many distinct events this endpoint has delivery attempts for, ignoring `limit` and `offset`. Use it to decide whether another page is worth requesting.",
      "example": 2
     },
     "limit": {
      "type": "integer",
      "description": "The page size actually applied, which is clamped to between 1 and 100 whatever you request.",
      "example": 50
     },
     "offset": {
      "type": "integer",
      "description": "How many events were skipped before this page. Add `limit` to it to request the next page.",
      "example": 0
     }
    },
    "required": [
     "items",
     "total",
     "limit",
     "offset"
    ]
   },
   "WebhookEventAttempt": {
    "type": "object",
    "description": "A single delivery attempt for an event.",
    "properties": {
     "attempt_id": {
      "type": "string",
      "description": "Identifies this single delivery attempt. Quote it when you contact support about a delivery you cannot account for.",
      "example": "wha_8e42bc52310ceff8bed0ff7664efd4ed"
     },
     "attempt_no": {
      "type": "integer",
      "description": "Where this attempt sits in the retry sequence for the event, starting at `1` for the original send. A high number means the event has been retried repeatedly and your endpoint has been rejecting it.",
      "example": 2
     },
     "status": {
      "type": "string",
      "description": "How this attempt ended. `pending`: queued and not yet sent. `succeeded`: your endpoint answered with a 2xx. `failed`: your endpoint answered with a non-2xx or could not be reached, and the event is retried on a backoff.",
      "example": "succeeded"
     },
     "callback_url": {
      "type": "string",
      "description": "The URL this attempt was sent to, captured at send time, so an attempt made before you changed the endpoint's `url` still shows where it actually went. It is `null` on attempts recorded without a resolved destination.",
      "format": "uri",
      "example": "https://api.example.com/webhooks/bachs",
      "nullable": true
     },
     "http_status": {
      "type": "integer",
      "description": "The HTTP status code your endpoint returned. It is `null` when the request never completed, for example on a DNS failure or a timeout, which is how you tell a transport failure from a rejection.",
      "example": 200,
      "nullable": true
     },
     "response_snippet": {
      "type": "string",
      "description": "The first part of your endpoint's response body, kept so you can see what your own handler replied without adding logging on your side. It is `null` when no response body was received.",
      "example": "{\"received\":true}",
      "nullable": true
     },
     "last_error": {
      "type": "string",
      "description": "Why this attempt failed, as a short diagnostic string you can act on, for example a timeout, a TLS failure, or the rejecting status code. It is `null` when the attempt succeeded.",
      "example": null,
      "nullable": true
     },
     "created_at": {
      "type": "string",
      "description": "When the attempt was queued, as an ISO 8601 timestamp in UTC.",
      "example": "2026-03-09T10:02:41.000Z"
     },
     "updated_at": {
      "type": "string",
      "description": "When the attempt reached its final status, as an ISO 8601 timestamp in UTC. Subtract `created_at` from it to see how long your endpoint took to answer.",
      "example": "2026-03-09T10:02:41.000Z"
     }
    },
    "required": [
     "attempt_id",
     "attempt_no",
     "status",
     "created_at",
     "updated_at"
    ]
   },
   "WebhookEventDetail": {
    "type": "object",
    "description": "A webhook event with its full payload and delivery attempts.",
    "properties": {
     "event_id": {
      "type": "string",
      "description": "Identifies this event everywhere it appears, including as `id` inside the delivered payload, so you can use it as your deduplication key when you process a redelivery.",
      "example": "evt_5d50b401e3e47948235c374ae57b8807"
     },
     "event_type": {
      "type": "string",
      "description": "What happened, in `resource.action` form, for example `customer.created` or `payout.paid`. Branch on this before reading `payload`.",
      "example": "customer.created"
     },
     "entity_type": {
      "type": "string",
      "description": "The kind of resource the event is about, for example `customer`, `charge`, `payout`, `refund`, or `checkout`. It is `null` when the event carries no identifiable resource.",
      "example": "customer",
      "nullable": true
     },
     "entity_id": {
      "type": "string",
      "description": "The identifier of the resource named by `entity_type`, matching the id you would use to fetch that resource from its own endpoint. It is `null` when the event carries no identifiable resource.",
      "example": "cust_9ae63038729d2d6b793423bdbc27c19a",
      "nullable": true
     },
     "created_at": {
      "type": "string",
      "description": "When the event was recorded, as an ISO 8601 timestamp in UTC. This is the moment the change happened, not the moment it was delivered.",
      "example": "2026-03-09T10:00:00.000Z"
     },
     "payload": {
      "type": "object",
      "description": "The exact JSON body sent to your endpoint, byte for byte. It wraps the resource in an envelope of `id`, `type`, `created_at`, `organization_id`, and `data`, and adds `account` when the event came from an account you own. Replay this against your handler to reproduce a delivery."
     },
     "attempts": {
      "type": "array",
      "description": "Every delivery attempt made for this event, newest attempt number first. Read the first entry to see the current state and the rest to see what your endpoint returned on earlier tries.",
      "items": {
       "$ref": "#/components/schemas/WebhookEventAttempt"
      }
     }
    },
    "required": [
     "event_id",
     "event_type",
     "created_at",
     "payload",
     "attempts"
    ]
   },
   "ResendWebhookEventResponse": {
    "type": "object",
    "description": "The result of re-delivering an event.",
    "properties": {
     "status": {
      "type": "string",
      "description": "Always `queued` on success. The redelivery is asynchronous, so a `queued` response means the attempt was accepted, not that your endpoint has received it; poll the event's `attempts` to see the outcome.",
      "example": "queued"
     },
     "attempt_id": {
      "type": "string",
      "description": "The new delivery attempt created by this call. Match it against the `attempts` array on [Get Event](/api-reference/webhooks/get-webhook-event) to see whether the redelivery succeeded.",
      "example": "wha_8e42bc52310ceff8bed0ff7664efd4ed"
     }
    },
    "required": [
     "status",
     "attempt_id"
    ]
   },
   "DeleteWebhookEndpointResponse": {
    "type": "object",
    "description": "Confirmation that an endpoint was deleted.",
    "properties": {
     "status": {
      "type": "string",
      "description": "Always `deleted` on success. The endpoint stops receiving events immediately and its signing secret can no longer be read.",
      "example": "deleted"
     },
     "endpoint_id": {
      "type": "string",
      "description": "Echoes the endpoint you deleted so you can reconcile the call against your own records.",
      "example": "whe_a1e823c073ab743ce5969ceef2db4d42"
     }
    },
    "required": [
     "status",
     "endpoint_id"
    ]
   },
   "TrialPeriod": {
    "type": "object",
    "description": "The length of the free trial before the first charge, expressed as a count of time units. For example, `{ \"interval\": \"day\", \"frequency\": 14 }` is a 14-day trial.",
    "properties": {
     "interval": {
      "type": "string",
      "enum": [
       "day",
       "week",
       "month",
       "year"
      ],
      "description": "The unit of time the trial is measured in: `day`, `week`, `month`, or `year`.",
      "example": "day"
     },
     "frequency": {
      "type": "integer",
      "description": "How many `interval` units the trial lasts. For example, `interval` `day` with `frequency` `14` is a 14-day trial.",
      "example": 14
     }
    },
    "required": [
     "interval",
     "frequency"
    ]
   },
   "CreateTransferRequest": {
    "type": "object",
    "required": [
     "destination",
     "amount",
     "currency"
    ],
    "properties": {
     "destination": {
      "type": "string",
      "description": "The account to credit, or `self` to send funds back to your platform when acting as an account you own with `X-Account-Id`. The debited side is always whoever is authenticated, so there is no source field.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     "amount": {
      "type": "string",
      "description": "Amount to move as a decimal string in `currency`, e.g. \"7000.00\". Always two decimal places. Must be greater than zero.",
      "example": "7000.00"
     },
     "currency": {
      "type": "string",
      "minLength": 3,
      "maxLength": 10,
      "description": "Three-letter ISO 4217 currency code for the transfer, e.g. `NGN`. Both balances must already hold this currency; a transfer never converts.",
      "example": "NGN"
     },
     "description": {
      "type": "string",
      "maxLength": 500,
      "nullable": true,
      "description": "An arbitrary string attached to the transfer and returned unchanged. Useful for naming the order or invoice the share belongs to.",
      "example": "Order #4471 seller share"
     },
     "metadata": {
      "type": "object",
      "additionalProperties": true,
      "nullable": true,
      "description": "Your own key-value data, returned unchanged on the transfer. Not used by Bachs for processing."
     },
     "transfer_group": {
      "type": "string",
      "maxLength": 255,
      "nullable": true,
      "description": "Tags this transfer as part of a group, so several shares funded by the same charge can be reconciled together. Reuse the same value across every transfer for one charge, including a later recovery.",
      "example": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f"
     }
    }
   },
   "TransferResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "description": "Unique identifier for this transfer.",
      "example": "tr_8c1e04a7b93f2d6540ab"
     },
     "source": {
      "type": "string",
      "description": "Whoever was debited. Your platform when sending a share to an account you own, the account when recovering one.",
      "example": "acct_7KpQ2mNv4XbR9dLc"
     },
     "destination": {
      "type": "string",
      "description": "Whoever was credited.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     "amount": {
      "type": "string",
      "description": "The amount moved, as a decimal string in `currency`.",
      "example": "7000.00"
     },
     "currency": {
      "type": "string",
      "description": "Three-letter ISO 4217 currency code the transfer moved.",
      "example": "NGN"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "paid"
      ],
      "description": "Whether the funds have moved. `paid`: the balances have been updated. `pending`: the transfer exists but its movement has not been recorded yet. Derived from the underlying movement, so it never disagrees with the balances.",
      "example": "paid"
     },
     "description": {
      "type": "string",
      "nullable": true,
      "description": "The description you supplied on creation.",
      "example": "Order #4471 seller share"
     },
     "metadata": {
      "type": "object",
      "additionalProperties": true,
      "description": "The metadata you supplied on creation, returned unchanged."
     },
     "transfer_group": {
      "type": "string",
      "nullable": true,
      "description": "The group you supplied on creation, or `null` when the transfer was not tagged.",
      "example": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f"
     },
     "kind": {
      "type": "string",
      "enum": [
       "payout",
       "manual"
      ],
      "description": "What this movement is. `payout` is a seller's share of a sale you made, and `manual` is a transfer you created yourself. The platform's own cut of a sale is never a transfer; read it at [Platform fees](/connect/platform-fees).",
      "example": "manual"
     },
     "source_charge_id": {
      "type": "string",
      "nullable": true,
      "description": "The charge that funded this movement, when one did. Null on a transfer you created yourself, which is tied to nothing.",
      "example": null
     },
     "created_at": {
      "type": "string",
      "description": "When the transfer was created, ISO 8601 in UTC.",
      "example": "2026-08-07T11:04:22.518Z"
     }
    }
   },
   "TransferListResponse": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/TransferResponse"
      },
      "description": "The transfers on this page, newest first."
     },
     "pagination": {
      "$ref": "#/components/schemas/PaginationResponse"
     }
    }
   },
   "PlatformFeeResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "description": "The platform fee's unique identifier, prefixed `pf_`.",
      "example": "pf_8c1e04a7b93f2d6540ab1234"
     },
     "charge": {
      "type": "string",
      "description": "The charge that this fee was struck against, prefixed `ch_`.",
      "example": "ch_9f4c1d2e7b6a4f8e9c0d1a2b3c4d5e6f"
     },
     "collected_from": {
      "type": "string",
      "description": "The account the fee was collected from: the seller on a destination charge, or the merchant itself on a direct charge.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     "earned_by": {
      "type": "string",
      "description": "The platform that earned the fee.",
      "example": "acct_7KpQ2mNv4XbR9dLc"
     },
     "amount": {
      "type": "string",
      "description": "The fee amount, as a decimal string in `currency`.",
      "example": "20000.00"
     },
     "currency": {
      "type": "string",
      "description": "The currency the sale was struck in, before any conversion, as an ISO 4217 code.",
      "example": "NGN"
     },
     "amount_refunded": {
      "type": "string",
      "description": "How much of this fee has been reversed. Currently always `\"0.00\"`: a platform fee is not reversed when its charge is refunded.",
      "example": "0.00"
     },
     "refunded": {
      "type": "boolean",
      "description": "Whether the fee has been fully reversed. Derived from `amount_refunded` against `amount`, so it cannot disagree with them.",
      "example": false
     },
     "created_at": {
      "type": "string",
      "description": "When the fee was recorded, ISO 8601 in UTC.",
      "example": "2026-08-07T11:04:22.518Z"
     }
    }
   },
   "PlatformFeeListResponse": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/PlatformFeeResponse"
      },
      "description": "The platform fees on this page, newest first."
     },
     "pagination": {
      "$ref": "#/components/schemas/PaginationResponse",
      "description": "Pagination cursors and counts. See the Pagination guide."
     }
    }
   },
   "CapabilityStatusDetail": {
    "type": "object",
    "properties": {
     "code": {
      "type": "string",
      "description": "Machine-readable reason the capability is not active. Branch on this rather than on `message`.",
      "example": "platform_disabled"
     },
     "resolution": {
      "type": "string",
      "nullable": true,
      "description": "What has to happen for the capability to become active.",
      "example": "Contact support to re-enable this capability."
     },
     "message": {
      "type": "string",
      "nullable": true,
      "description": "Human-readable explanation, safe to show the account holder.",
      "example": "This capability was disabled by the platform."
     }
    }
   },
   "AccountCapabilityStatus": {
    "type": "object",
    "properties": {
     "status": {
      "type": "string",
      "enum": [
       "active",
       "pending",
       "restricted",
       "unrequested",
       "unsupported"
      ],
      "description": "Whether the account may perform this action. `active`: enabled, and the only value that authorizes anything. `pending`: requested or submitted, awaiting review. `restricted`: not enabled, and the default. `unrequested`: the account has no record for this capability, which differs from `restricted` in that it was never asked for. `unsupported`: the account is not eligible for this capability.",
      "example": "active"
     },
     "requested": {
      "type": "boolean",
      "description": "Whether the account ever requested this capability. A `restricted` capability that was requested is in progress; one that was never requested is outside the account's setup.",
      "example": true
     },
     "status_details": {
      "type": "array",
      "nullable": true,
      "items": {
       "$ref": "#/components/schemas/CapabilityStatusDetail"
      },
      "description": "Why the capability is not active. `null` when the capability is `active`, meaning there is nothing to explain."
     }
    }
   },
   "RequirementError": {
    "type": "object",
    "properties": {
     "field": {
      "type": "string",
      "description": "The field key that was rejected.",
      "example": "persons.per_3a91c0d7.id_document"
     },
     "code": {
      "type": "string",
      "nullable": true,
      "description": "Machine-readable rejection reason.",
      "example": "unreadable"
     },
     "reason": {
      "type": "string",
      "nullable": true,
      "description": "Human-readable rejection reason, safe to show the account holder.",
      "example": "The document image was too blurry to read."
     }
    }
   },
   "AccountRequirements": {
    "type": "object",
    "description": "The account-wide roll-up of outstanding requirements. Populated on single-account reads only.",
    "properties": {
     "currently_due": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Field keys required now.",
      "example": [
       "company.registration_number"
      ]
     },
     "eventually_due": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Field keys required later, once a threshold or stage is reached.",
      "example": []
     },
     "past_due": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Field keys that were required by a date now passed.",
      "example": []
     },
     "pending_verification": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Field keys provided and being checked.",
      "example": [
       "persons.per_3a91c0d7.id_document"
      ]
     },
     "errors": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/RequirementError"
      },
      "description": "Fields that were provided and then rejected, as distinct from fields that are missing."
     },
     "entries": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/RequirementEntry"
      },
      "description": "Per-field view of the same requirements, each carrying the capabilities it blocks."
     },
     "values": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/TaskValueItem"
      },
      "description": "Only present with `include=requirements.values`. Account-level fields and their current values, for reading back what was submitted and prefilling an edit. Sensitive fields are listed as provided and never echoed. People are returned separately under `persons`."
     },
     "persons": {
      "type": "array",
      "items": {
       "type": "object",
       "additionalProperties": true
      },
      "description": "One entry per person on the account, rolled up rather than split into fields. Each entry carries `id`, `first_name`, `last_name`, `dob`, `address`, `address_reference_data`, `relationship`, `id_document_provided`, and `verification_status`. Identity documents are summarised by the `id_document_provided` flag and never returned. Only present with `include=requirements.values`."
     },
     "current_deadline": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "The soonest deadline across everything outstanding, for a single banner. Null when no outstanding field carries one."
     }
    }
   },
   "ResponsibilitiesResponse": {
    "type": "object",
    "properties": {
     "fees": {
      "type": "object",
      "description": "Who collects the Bachs processing fee on this account's charges.",
      "properties": {
       "collector": {
        "type": "string",
        "enum": [
         "platform",
         "bachs"
        ],
        "description": "`bachs`: the fee comes out of the charge and the account settles net. `platform`: the platform absorbs the fee and the account settles gross. Set when the account is created and immutable afterwards.",
        "example": "bachs"
       }
      }
     }
    }
   },
   "ConnectedAccountListResponse": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/OrganizationResponse"
      },
      "description": "The accounts on this page. Items never carry `capabilities` or `requirements`; read a single account for those."
     },
     "total": {
      "type": "integer",
      "description": "Total accounts, across all pages.",
      "example": 42
     },
     "limit": {
      "type": "integer",
      "description": "The page size used for this response.",
      "example": 20
     },
     "offset": {
      "type": "integer",
      "description": "The offset used for this response.",
      "example": 0
     }
    }
   },
   "CapabilityRequest": {
    "type": "object",
    "properties": {
     "requested": {
      "type": "boolean",
      "default": false,
      "description": "Set to `true` to request this capability for the account, which applies the configuration the capability belongs to and surfaces the requirements it needs. Requesting authorizes nothing on its own. `false` is rejected with `400 capability_unrequest_unsupported`, because there is no path to withdraw a capability once it has been requested.",
      "example": true
     }
    }
   },
   "AccountConfigurationOptions": {
    "type": "object",
    "description": "A named persona, and the capabilities requested under it. `capabilities` omitted requests every capability that persona allows on create (never on update); `{}` requests none.",
    "properties": {
     "capabilities": {
      "type": "object",
      "nullable": true,
      "additionalProperties": {
       "$ref": "#/components/schemas/CapabilityRequest"
      },
      "description": "Capabilities requested under this persona, keyed by name. Omitting this on create requests every capability the persona allows; omitting it on update just applies the persona and requests nothing. Send `{}` to apply the persona and request nothing, on either endpoint. An unrecognised or inactive capability name is rejected with `400 unknown_capability`.",
      "example": {
       "card_collection": {
        "requested": true
       }
      }
     }
    }
   },
   "ResponsibilitiesRequest": {
    "type": "object",
    "description": "Fee arrangement for the account. Set once at creation and immutable afterwards.",
    "properties": {
     "fees": {
      "type": "object",
      "description": "Who collects the Bachs processing fee on this account's charges. Defaults to `bachs`.",
      "properties": {
       "collector": {
        "type": "string",
        "enum": [
         "platform",
         "bachs"
        ],
        "default": "bachs",
        "description": "`bachs`: the fee comes out of the charge and the account settles net. `platform`: the platform absorbs the fee on this account's charges and the account settles gross.",
        "example": "platform"
       }
      }
     }
    }
   },
   "CreateConnectedAccountRequest": {
    "type": "object",
    "required": [
     "contact_email"
    ],
    "properties": {
     "contact_email": {
      "type": "string",
      "format": "email",
      "description": "Email address of the person or business behind the account. Trimmed and lowercased before it is stored.",
      "example": "ada@adastores.example"
     },
     "display_name": {
      "type": "string",
      "nullable": true,
      "description": "Name you want the account listed under. Becomes the account's `name`, and is `null` until the account holder sets one during onboarding if you omit it.",
      "example": "Ada Stores"
     },
     "first_name": {
      "type": "string",
      "maxLength": 255,
      "nullable": true,
      "description": "Given name of the person you are onboarding, used to label the account before verification collects a legal name. Whitespace-only values are stored as `null`.",
      "example": "Ada"
     },
     "last_name": {
      "type": "string",
      "maxLength": 255,
      "nullable": true,
      "description": "Family name of the person you are onboarding. Whitespace-only values are stored as `null`.",
      "example": "Okafor"
     },
     "country": {
      "type": "string",
      "nullable": true,
      "description": "Two-letter ISO 3166-1 country code for the account. Decides which requirements the account is given, so set it when you already know it. Falls back to your own platform's country.",
      "example": "NG"
     },
     "entity_type": {
      "type": "string",
      "enum": [
       "company",
       "individual"
      ],
      "nullable": true,
      "description": "What kind of legal person the account is, which together with `country` decides the requirements it is given. `company`: a registered entity, asked for registration and ownership details. `individual`: a natural person, asked only for their own identity.",
      "example": "company"
     },
     "configuration": {
      "type": "object",
      "nullable": true,
      "additionalProperties": {
       "$ref": "#/components/schemas/AccountConfigurationOptions"
      },
      "description": "Personas the account is being created for, keyed by name (`merchant`, `recipient`). No persona is ever applied automatically, `recipient` included. An account created with no `configuration` holds neither and cannot hold any capability. Sending an empty object is rejected with `422 VALIDATION_ERROR`; omit the field entirely for a persona-less account instead. A capability is only ever named inside the persona object it belongs to, in its `capabilities`, so naming one always names its persona in the same request; there is no way to name a capability without also naming a persona, and no way to infer one from a bare capability name. A capability nested under the wrong persona for it is rejected with `400 capability_configuration_mismatch`. There is no field to apply a configuration after creation other than naming it again on update, so decide every persona the account will ever need up front, or add one later on `POST /v1/accounts/{account_id}`. An unrecognised key is rejected with `400 invalid_configuration`.",
      "example": {
       "merchant": {
        "capabilities": {
         "card_collection": {
          "requested": true
         }
        }
       }
      },
      "minProperties": 1
     },
     "responsibilities": {
      "allOf": [
       {
        "$ref": "#/components/schemas/ResponsibilitiesRequest"
       }
      ],
      "description": "Fee arrangement for the account. Defaults to Bachs collecting its fee out of the charge."
     }
    }
   },
   "ConnectedAccountCapability": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "enum": [
       "payouts",
       "transfers",
       "conversions",
       "connect"
      ],
      "description": "The action this entry governs. `payouts`: withdraw from the account's balance to a bank or wallet. `transfers`: move funds between your balance and the account's. `conversions`: convert between currencies the account holds. `connect`: create and onboard accounts of its own.",
      "example": "payouts"
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "pending",
       "restricted",
       "unrequested",
       "unsupported"
      ],
      "description": "Whether the account may perform this action. `active`: enabled, and the only value that authorizes anything. `pending`: requested or submitted, awaiting review. `restricted`: not enabled, and the default. `unrequested`: no record exists for this capability, which differs from `restricted` in that it was never asked for. `unsupported`: the account is not eligible for this capability at all.",
      "example": "active"
     },
     "requested": {
      "type": "boolean",
      "description": "Whether the account ever requested this capability. A `restricted` capability that was requested is in progress; one that was never requested is outside the account's setup.",
      "example": true
     },
     "status_details": {
      "type": "array",
      "nullable": true,
      "items": {
       "$ref": "#/components/schemas/CapabilityStatusDetail"
      },
      "description": "Why the capability is not active. `null` when the capability is `active`, meaning there is nothing to explain."
     }
    }
   },
   "ConnectedAccountCapabilitiesResponse": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ConnectedAccountCapability"
      },
      "description": "Every capability applicable to the account, including ones it has never requested. Capabilities the account is not eligible to hold at all are omitted rather than returned as `unsupported`."
     }
    }
   },
   "CreateAccountLinkRequest": {
    "type": "object",
    "required": [
     "type",
     "refresh_url",
     "return_url"
    ],
    "properties": {
     "type": {
      "type": "string",
      "enum": [
       "onboarding",
       "update"
      ],
      "description": "What the account holder is being sent to do. `onboarding`: collect everything the account still owes for the first time. `update`: revisit information already collected, which requires the account to have requirements already and otherwise fails with `400 CONNECTED_ACCOUNT_REQUIREMENTS_NOT_FOUND`.",
      "example": "onboarding"
     },
     "refresh_url": {
      "type": "string",
      "format": "uri",
      "description": "Where the account holder is sent when the link is no longer usable, for example after it expired. Issue a fresh link from the page you point at, because the original URL cannot be revived.",
      "example": "https://adastores.example/connect/refresh"
     },
     "return_url": {
      "type": "string",
      "format": "uri",
      "description": "Where the account holder is sent when they finish or abandon the flow. Arriving here is not proof that onboarding completed, so confirm from the `account.updated` event rather than from the redirect.",
      "example": "https://adastores.example/connect/return"
     },
     "collection_options": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Options carried through to the hosted flow and handed back unchanged when the link is opened. Omit it unless you were given specific keys to send."
     }
    }
   },
   "AccountLinkResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "description": "Unique identifier for the account link.",
      "example": "alnk_3b7e12c9d4a05f68b1c2"
     },
     "object": {
      "type": "string",
      "enum": [
       "connected_account_link"
      ],
      "description": "Always `connected_account_link`, so a mixed webhook or log stream can be routed on type.",
      "example": "connected_account_link"
     },
     "account": {
      "type": "string",
      "description": "The account this link onboards.",
      "example": "acct_3Wq8ZfT1yHnJ5sVe"
     },
     "type": {
      "type": "string",
      "enum": [
       "onboarding",
       "update"
      ],
      "description": "What the link was issued for, echoing the `type` you sent. `onboarding`: the account holder is walked through everything the account still owes, for the first time. `update`: the account holder revisits information already collected, which only works once the account has requirements and otherwise fails with `400 CONNECTED_ACCOUNT_REQUIREMENTS_NOT_FOUND`.",
      "example": "onboarding"
     },
     "created": {
      "type": "string",
      "format": "date-time",
      "description": "When the link was issued, ISO 8601 in UTC.",
      "example": "2026-08-07T11:04:22.518Z"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the link stops working, ISO 8601 in UTC. After this the account holder lands on your `refresh_url` instead. Read this value rather than assuming a fixed lifetime.",
      "example": "2026-09-06T11:04:22.518Z"
     },
     "url": {
      "type": "string",
      "description": "Send the account holder here. The URL carries a single-use credential, so deliver it over a channel you trust and keep it out of logs and analytics. It is returned only on this response and cannot be read back.",
      "example": "https://connect.bachs.io/setup/c/acct_3Wq8ZfT1yHnJ5sVe/al_kQ2v8nS1xJd0pR7mLtY4wZ6aHb3cFg9e"
     },
     "previous_link_superseded": {
      "type": "boolean",
      "description": "`true` when issuing this link invalidated an outstanding active link of the same `type` for the account. Generating a link on every page render keeps invalidating the one you already sent, so create a link when you are about to redirect and not before.",
      "example": false
     }
    }
   },
   "TaskValueItem": {
    "type": "object",
    "description": "One field's current value, for reading back what the account already provided and prefilling an edit form.",
    "properties": {
     "field": {
      "type": "string",
      "description": "Canonical key for the field, the same key you submit it under.",
      "example": "business_profile.url"
     },
     "label": {
      "type": "string",
      "description": "Human-readable name for the field, safe to show the account holder verbatim.",
      "example": "Business website"
     },
     "group": {
      "type": "string",
      "nullable": true,
      "description": "Which onboarding section the field is shown in: `identity_verification`, `business_ownership`, `product_information`, or `bank_verification`. Note this is a coarser grouping than the `group` on a checklist field. `null` when the field maps to no section.",
      "example": "product_information"
     },
     "provided": {
      "type": "boolean",
      "description": "Whether the account has a value for this field. A sensitive field reports `provided: true` with no `value`.",
      "example": true
     },
     "sensitive": {
      "type": "boolean",
      "description": "When `true`, the value is never echoed back: `value` stays `null` and `display` reads `Provided`. Identity documents and bank account numbers are sensitive, so an edit form has to collect them again rather than prefill them.",
      "example": false
     },
     "value": {
      "nullable": true,
      "description": "The raw value, suitable for prefilling an edit form. Always `null` when `sensitive` is `true`.",
      "example": "https://adastores.example"
     },
     "display": {
      "type": "string",
      "nullable": true,
      "description": "One-line summary of the value for a review card. `Provided` for a sensitive field, and `null` when nothing has been provided.",
      "example": "https://adastores.example"
     },
     "reference_data": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Resolved labels for a value that is stored as a code, such as the name behind a bank code, so a review card does not have to look them up. `null` when the field has nothing to resolve."
     }
    }
   },
   "TaskBankListResponse": {
    "type": "object",
    "properties": {
     "country": {
      "type": "string",
      "description": "Two-letter ISO 3166-1 country the list was resolved for, uppercased.",
      "example": "NG"
     },
     "banks": {
      "type": "array",
      "description": "Banks you can submit as a payout destination for this country.",
      "items": {
       "type": "object",
       "properties": {
        "name": {
         "type": "string",
         "description": "Bank name to show the account holder.",
         "example": "Providus Bank"
        },
        "code": {
         "type": "string",
         "description": "Code to send as `bank_code` when resolving an account or submitting a payout destination.",
         "example": "101"
        }
       }
      }
     }
    }
   },
   "TaskMobileMoneyListResponse": {
    "type": "object",
    "properties": {
     "country": {
      "type": "string",
      "description": "Two-letter ISO 3166-1 country the list was resolved for, uppercased.",
      "example": "GH"
     },
     "providers": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Mobile money provider names available in this country, deduplicated and in display order. Empty when the country has none.",
      "example": [
       "MTN",
       "Vodafone",
       "AirtelTigo"
      ]
     }
    }
   },
   "ResolveTaskBankAccountRequest": {
    "type": "object",
    "required": [
     "account_number",
     "bank_code"
    ],
    "properties": {
     "account_number": {
      "type": "string",
      "description": "The account number to look up, digits only and exactly as the account holder typed it.",
      "example": "0123456789"
     },
     "bank_code": {
      "type": "string",
      "description": "Code of the bank holding the account, taken from `code` on the bank list.",
      "example": "101"
     },
     "country": {
      "type": "string",
      "nullable": true,
      "description": "Two-letter ISO 3166-1 country to resolve in. Falls back to the account's country, and a country outside `NG` and `GH` comes back as `resolved: false` rather than an error.",
      "example": "NG"
     }
    }
   },
   "ResolveTaskBankAccountResponse": {
    "type": "object",
    "properties": {
     "resolved": {
      "type": "boolean",
      "description": "Whether the account number was matched. `false` covers a wrong number, an unsupported country, and a lookup that could not be completed, so read `message` to tell them apart. A `false` here is not an HTTP error.",
      "example": true
     },
     "account_name": {
      "type": "string",
      "nullable": true,
      "description": "Name registered on the account. Show it back for confirmation before you submit the payout destination. `null` when `resolved` is `false`.",
      "example": "ADA OKAFOR"
     },
     "account_number": {
      "type": "string",
      "nullable": true,
      "description": "The account number as it is held on record, which can be normalised from what you sent. `null` when `resolved` is `false`.",
      "example": "0123456789"
     },
     "message": {
      "type": "string",
      "nullable": true,
      "description": "Why the lookup did not resolve, safe to show the account holder. `null` on a successful match.",
      "example": null
     }
    }
   },
   "CreatePayoutRequest": {
    "type": "object",
    "description": "Send money to a registered destination. Exactly one of `amount` or `quote_id` is required, never both and never neither. `amount` funds a same-currency payout; `quote_id` funds a cross-currency payout, since the quote already fixes both sides.",
    "required": [
     "destination"
    ],
    "properties": {
     "destination": {
      "type": "string",
      "description": "The ID of a payout destination belonging to your account. The destination must be usable (`is_usable: true`).",
      "example": "pd_7Kq2mNv4XbR9dLc0"
     },
     "amount": {
      "type": "string",
      "nullable": true,
      "description": "The amount the destination should receive, as a decimal string (e.g. \"5000.00\"), in the destination's currency. The fee is charged on top of this amount, not deducted from it. Omit when supplying `quote_id`.",
      "example": "5000.00"
     },
     "quote_id": {
      "type": "string",
      "nullable": true,
      "description": "A quote ID from Create Payout Quote. Required for cross-currency payouts, where the source currency differs from the destination's currency. Omit `amount` when supplying this field.",
      "example": null
     },
     "reference": {
      "type": "string",
      "maxLength": 128,
      "nullable": true,
      "description": "Your own reference for this payout, up to 128 characters. Omit it and the payout has none; use the payout's `id` to track it.",
      "example": "payout-2026-08-07-001"
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Arbitrary key-value data to attach to the payout.",
      "example": null
     }
    }
   },
   "CreatePayoutResponse": {
    "$ref": "#/components/schemas/PayoutResponse"
   },
   "CreatePayoutDestinationRequest": {
    "type": "object",
    "description": "Register where money should land. Accepts both the field names this surface has always used and newer aliases, so a caller never has to know which generation of the API it is talking to. Where a legacy name and its alias overlap, the newer name wins.",
    "required": [
     "currency"
    ],
    "properties": {
     "name": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "User-friendly name for this destination.",
      "example": "My GTBank Savings"
     },
     "label": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "Alias for `name`. `name` wins if both are sent.",
      "example": null
     },
     "currency": {
      "type": "string",
      "maxLength": 10,
      "description": "Currency code this destination accepts (e.g., 'NGN', 'USD', 'USDT_TRC20').",
      "example": "NGN"
     },
     "type": {
      "type": "string",
      "nullable": true,
      "description": "Type of payout destination: `bank_account`, `mobile_money`, or `crypto_wallet`. Inferred from `currency` when omitted.",
      "example": "bank_account"
     },
     "destination_type": {
      "type": "string",
      "nullable": true,
      "description": "Alias for `type`. `type` wins if both are sent.",
      "example": null
     },
     "account_number": {
      "type": "string",
      "nullable": true,
      "maxLength": 50,
      "description": "Bank account number. Required for bank_account destinations.",
      "example": "0123456789"
     },
     "bank_code": {
      "type": "string",
      "nullable": true,
      "maxLength": 20,
      "description": "Bank code or routing number. Required for bank_account destinations.",
      "example": "058"
     },
     "account_name": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "Accepted for compatibility and ignored, because the account holder name is always resolved from the bank.",
      "example": null
     },
     "bank_name": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "Accepted for compatibility and ignored, because the bank name is always resolved from the bank.",
      "example": null
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "maxLength": 20,
      "description": "Phone number for the mobile money account. Required for mobile_money destinations.",
      "example": null
     },
     "mobile_provider": {
      "type": "string",
      "nullable": true,
      "maxLength": 50,
      "description": "Mobile money provider (e.g., 'MTN', 'Vodafone'). Required for mobile_money destinations.",
      "example": null
     },
     "wallet_address": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "Cryptocurrency wallet address. Required for crypto_wallet destinations.",
      "example": null
     },
     "network": {
      "type": "string",
      "nullable": true,
      "maxLength": 50,
      "description": "Blockchain network. Optional when the currency already names its network (e.g. USDT_TRC20).",
      "example": null
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Additional custom metadata to associate with this destination.",
      "example": null
     }
    }
   },
   "UpdatePayoutDestinationRequest": {
    "type": "object",
    "description": "The one update a destination allows. `name` and `is_default` alone are safe: a rename touches no routing column, and the default can only ever be one of your own approved destinations. Sending any field below restates the destination in full, the same shape as `POST`; omitted routing fields fall back to what is already stored. Changing an account number, bank code, wallet, network or phone number this way sends the destination back for review, because the approval it holds was granted for the details it is being asked to leave behind.",
    "properties": {
     "name": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "minLength": 1,
      "description": "The new name for this destination.",
      "example": "Treasury NGN Account"
     },
     "is_default": {
      "type": "boolean",
      "nullable": true,
      "description": "Make this the destination a payout schedule pays out to for its currency. Setting it demotes the previous default; false clears it. Ignored if this request also changes where money lands and that change sends the destination back for review.",
      "example": true
     },
     "currency": {
      "type": "string",
      "nullable": true,
      "maxLength": 10,
      "description": "Currency code this destination accepts (e.g., 'NGN', 'USD', 'USDT_TRC20').",
      "example": null
     },
     "type": {
      "type": "string",
      "nullable": true,
      "description": "Type of payout destination: `bank_account`, `mobile_money`, or `crypto_wallet`.",
      "example": null
     },
     "destination_type": {
      "type": "string",
      "nullable": true,
      "description": "Alias for `type`. `type` wins if both are sent.",
      "example": null
     },
     "account_number": {
      "type": "string",
      "nullable": true,
      "maxLength": 50,
      "description": "Bank account number.",
      "example": null
     },
     "account_name": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "Account holder name. Unlike registration, an update trusts the name it is given.",
      "example": null
     },
     "bank_code": {
      "type": "string",
      "nullable": true,
      "maxLength": 20,
      "description": "Bank code or routing number.",
      "example": null
     },
     "bank_name": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "Bank name.",
      "example": null
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "maxLength": 20,
      "description": "Phone number for the mobile money account.",
      "example": null
     },
     "mobile_provider": {
      "type": "string",
      "nullable": true,
      "maxLength": 50,
      "description": "Mobile money provider (e.g., 'MTN', 'Vodafone').",
      "example": null
     },
     "wallet_address": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "Cryptocurrency wallet address.",
      "example": null
     },
     "network": {
      "type": "string",
      "nullable": true,
      "maxLength": 50,
      "description": "Blockchain network. Optional when the currency already names its network (e.g. USDT_TRC20).",
      "example": null
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Additional custom metadata to associate with this destination.",
      "example": null
     }
    }
   },
   "PayoutDestinationResponse": {
    "type": "object",
    "description": "Response containing payout destination details (bank account, mobile money, or crypto wallet).",
    "required": [
     "id",
     "name",
     "type",
     "currency",
     "status"
    ],
    "properties": {
     "id": {
      "type": "string",
      "description": "Unique identifier for this payout destination. Use this ID when creating payouts.",
      "example": "pd_7Kq2mNv4XbR9dLc0"
     },
     "name": {
      "type": "string",
      "description": "User-friendly name for this destination. Helps you identify destinations in your system.",
      "example": "My GTBank Savings"
     },
     "type": {
      "type": "string",
      "enum": [
       "bank_account",
       "mobile_money",
       "crypto_wallet"
      ],
      "description": "Type of payout destination: `bank_account`, `mobile_money`, or `crypto_wallet`. Determines which fields are populated.",
      "example": "bank_account"
     },
     "currency": {
      "type": "string",
      "description": "Currency code this destination accepts (e.g., 'NGN', 'USD', 'USDT_TRC20'). Payouts to this destination must use this currency.",
      "example": "NGN"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending_review",
       "approved",
       "rejected"
      ],
      "description": "Review status. `pending_review`: awaiting review, not usable yet. `approved`: cleared for payouts. `rejected`: permanently unusable, register a new destination instead.",
      "example": "approved"
     },
     "status_reason": {
      "type": "string",
      "nullable": true,
      "description": "Free-text reason set by review, populated when the destination is rejected. Null while pending or approved.",
      "example": null
     },
     "is_usable": {
      "type": "boolean",
      "description": "Whether this destination can be used for a payout right now. True only when `status` is `approved` and the destination has not been deactivated.",
      "example": true
     },
     "is_default": {
      "type": "boolean",
      "description": "Whether a payout schedule pays out to this destination for its currency. Set it with `PATCH /v1/payouts/destinations/{destination_id}`.",
      "example": false
     },
     "account_number": {
      "type": "string",
      "nullable": true,
      "description": "Bank account number. Only populated for bank_account destinations.",
      "example": "0123456789"
     },
     "account_name": {
      "type": "string",
      "nullable": true,
      "description": "Account holder name as resolved from the bank. Only populated for bank_account destinations.",
      "example": "JOHN DOE"
     },
     "bank_code": {
      "type": "string",
      "nullable": true,
      "description": "Bank code or routing number. Only populated for bank_account destinations.",
      "example": "058"
     },
     "bank_name": {
      "type": "string",
      "nullable": true,
      "description": "Full name of the bank. Only populated for bank_account destinations.",
      "example": "Guaranty Trust Bank"
     },
     "phone_number": {
      "type": "string",
      "nullable": true,
      "description": "Phone number associated with the mobile money account. Only populated for mobile_money destinations.",
      "example": null
     },
     "mobile_provider": {
      "type": "string",
      "nullable": true,
      "description": "Mobile money provider (e.g., 'MTN', 'Vodafone'). Only populated for mobile_money destinations.",
      "example": null
     },
     "wallet_address": {
      "type": "string",
      "nullable": true,
      "description": "Cryptocurrency wallet address. Only populated for crypto_wallet destinations.",
      "example": null
     },
     "network": {
      "type": "string",
      "nullable": true,
      "description": "Blockchain network (e.g., 'TRC20', 'ERC20'). Only populated for crypto_wallet destinations. May be included in currency code (e.g., 'USDT_TRC20').",
      "example": null
     },
     "reviewed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when this destination was last reviewed by an admin. Null until reviewed.",
      "example": null
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when this destination was created.",
      "example": "2026-01-24T14:30:00.000Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "ISO 8601 timestamp when this destination was last updated.",
      "example": "2026-01-24T14:30:00.000Z"
     }
    }
   },
   "PayoutDestinationListResponse": {
    "type": "object",
    "description": "Paginated list of configured payout destinations. `total` counts every matching destination, not just the ones on this page.",
    "required": [
     "destinations",
     "total",
     "limit",
     "offset"
    ],
    "properties": {
     "destinations": {
      "type": "array",
      "description": "Array of payout destination objects.",
      "items": {
       "$ref": "#/components/schemas/PayoutDestinationResponse"
      }
     },
     "total": {
      "type": "integer",
      "description": "Total number of destinations matching the query, across all pages.",
      "example": 1
     },
     "limit": {
      "type": "integer",
      "description": "The `limit` used for this page of results.",
      "example": 20
     },
     "offset": {
      "type": "integer",
      "description": "The `offset` used for this page of results.",
      "example": 0
     }
    }
   },
   "DeletePayoutDestinationResponse": {
    "type": "object",
    "description": "Confirmation that a destination was deactivated.",
    "required": [
     "id",
     "deleted"
    ],
    "properties": {
     "id": {
      "type": "string",
      "description": "The ID of the destination that was deactivated.",
      "example": "pd_7Kq2mNv4XbR9dLc0"
     },
     "deleted": {
      "type": "boolean",
      "description": "Always true. Payouts already sent against this destination are unaffected.",
      "example": true
     }
    }
   },
   "RequirementEntry": {
    "type": "object",
    "description": "One outstanding requirement and what it holds up. The buckets say what is missing; this says what breaks while it is. Prefer this over the buckets when an account holds more than one capability.",
    "properties": {
     "field": {
      "type": "string",
      "description": "Canonical field key.",
      "example": "company.registration_number"
     },
     "status": {
      "type": "string",
      "description": "The bucket this entry is in.",
      "enum": [
       "currently_due",
       "eventually_due",
       "past_due",
       "pending_verification"
      ],
      "example": "currently_due"
     },
     "restricts_capabilities": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Capabilities this field blocks. Empty when no capability the account holds requires it.",
      "example": [
       "payouts"
      ]
     },
     "errors": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "code": {
         "type": "string",
         "nullable": true
        },
        "reason": {
         "type": "string",
         "nullable": true
        }
       }
      },
      "description": "Verification or rejection errors for this field."
     },
     "resolution": {
      "type": "string",
      "enum": [
       "api",
       "review"
      ],
      "description": "Who can act on this field. `api`: yours to supply, through the account update or the persons subresource. `review`: already provided and sitting with us, so re-sending it achieves nothing. Treat an unrecognized value as not yours to resolve.",
      "example": "api"
     },
     "deadline": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "When this field must be resolved by, if a deadline was set."
     }
    }
   },
   "PersonRelationship": {
    "type": "object",
    "description": "Role flags. One person is commonly several of these at once, which is why they are flags on one person rather than separate collections.",
    "properties": {
     "representative": {
      "type": "boolean",
      "description": "The person who controls the account and acts for it."
     },
     "owner": {
      "type": "boolean",
      "description": "A beneficial owner at or above the ownership threshold."
     },
     "director": {
      "type": "boolean",
      "description": "`true` when the person sits on the board of the company behind the account. It is independent of the other flags, so setting it does not clear `representative`, `owner` or `executive`.",
      "example": false
     },
     "executive": {
      "type": "boolean",
      "description": "`true` when the person is a senior manager of the company behind the account. It is independent of the other flags, so setting it does not clear `representative`, `owner` or `director`.",
      "example": false
     },
     "percent_ownership": {
      "type": "integer",
      "nullable": true,
      "description": "Percentage owned, when known."
     },
     "title": {
      "type": "string",
      "nullable": true,
      "description": "The person's job title at the company behind the account, for example `Founder` or `Chief Financial Officer`, or `null` when none was given.",
      "example": "Founder"
     }
    }
   },
   "PersonVerification": {
    "type": "object",
    "description": "What has been established about this person. How it was established is not reported.",
    "properties": {
     "status": {
      "type": "string",
      "enum": [
       "unverified",
       "pending",
       "verified",
       "failed"
      ]
     },
     "document_provided": {
      "type": "boolean",
      "description": "Whether an identity document is held."
     },
     "failure_reason": {
      "type": "string",
      "nullable": true,
      "description": "Written for display to the account holder."
     }
    }
   },
   "PersonResponse": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "per_3a91c0d7",
      "description": "The person's identifier, prefixed `per_`. Requirement keys are anchored to it, so `persons.per_3a91c0d7.id_document` names exactly who owes a document."
     },
     "first_name": {
      "type": "string",
      "nullable": true,
      "description": "The person's given name as recorded, or `null` when it has not been supplied yet. It is the name their identity document is checked against.",
      "example": "Ada"
     },
     "last_name": {
      "type": "string",
      "nullable": true,
      "description": "The person's family name as recorded, or `null` when it has not been supplied yet. It is checked against the identity document alongside `first_name`.",
      "example": "Obi"
     },
     "dob": {
      "type": "string",
      "nullable": true,
      "description": "ISO-8601 date, `YYYY-MM-DD`.",
      "example": "1990-04-12"
     },
     "address": {
      "type": "object",
      "additionalProperties": true,
      "nullable": true,
      "description": "The person's residential address, carrying the `line1`, `city`, `state`, `postal_code` and `country` keys that were written, or `null` when no address has been supplied. It is stored whole, so a later write replaces it rather than merging into it."
     },
     "phone": {
      "type": "string",
      "nullable": true,
      "description": "The contact number recorded for this person, returned exactly as it was sent, or `null` when none has been supplied.",
      "example": "+2348012345678"
     },
     "email": {
      "type": "string",
      "nullable": true,
      "description": "The email address recorded for this person, or `null` when none has been supplied. It belongs to the person, not to the account, so it differs from the account's `contact_email`.",
      "example": "ada@example.com"
     },
     "id_number_provided": {
      "type": "boolean",
      "description": "`true` when a government ID number is held for this person, `false` when none has been supplied. The number itself is write-only and never returned, so this flag is how you tell whether you still need to collect one.",
      "example": true
     },
     "relationship": {
      "$ref": "#/components/schemas/PersonRelationship"
     },
     "verification": {
      "$ref": "#/components/schemas/PersonVerification"
     },
     "created_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the person was added to the account, ISO 8601 in UTC.",
      "example": "2026-08-10T09:31:12.000Z"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the person record last changed, ISO 8601 in UTC. A verification outcome we record moves it as well as your own writes, so do not read it as the time of your last edit.",
      "example": "2026-08-11T14:05:40.219Z"
     }
    }
   },
   "PersonListResponse": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/PersonResponse"
      },
      "description": "The account's persons for this page, oldest first, each carrying the same shape as [reading one person](/connect/accounts#persons). The order is stable, so paging with `offset` neither repeats nor skips anyone."
     },
     "total": {
      "type": "integer",
      "description": "How many persons the account has in total, not how many came back on this page. Compare it against `offset` plus the length of `items` to know whether another page is waiting.",
      "example": 2
     },
     "limit": {
      "type": "integer",
      "description": "How many persons a page returns at most, echoing the `limit` you sent. It defaults to 50 and is capped at 100; anything outside 1 to 100 is rejected with `422`.",
      "example": 50
     },
     "offset": {
      "type": "integer",
      "description": "How many persons were skipped before this page, echoing the `offset` you sent. Add `limit` to it to ask for the next page, and stop once it reaches `total`.",
      "example": 0
     }
    }
   },
   "PersonWriteRequest": {
    "type": "object",
    "description": "On edit, omitted keys are left alone and an explicit `null` clears the field. Naming one relationship flag leaves the others as they were.",
    "properties": {
     "first_name": {
      "type": "string",
      "description": "The person's given name as it appears on their government ID, since a mismatch against the document is the most common reason identity verification is rejected. On an update, omitting this key leaves the stored value alone and sending it as `null` clears it.",
      "example": "Ada"
     },
     "last_name": {
      "type": "string",
      "description": "The person's family name as it appears on their government ID, checked against the document alongside `first_name`. On an update, omitting this key leaves the stored value alone and sending it as `null` clears it.",
      "example": "Obi"
     },
     "dob": {
      "type": "string",
      "description": "ISO-8601 date, `YYYY-MM-DD`."
     },
     "address": {
      "type": "object",
      "additionalProperties": true,
      "description": "The person's residential address, as an object with `line1`, `city`, `state` and `country` (two-letter ISO 3166-1), plus an optional `postal_code`. It is written whole rather than merged, so send every key you want kept; on an update, omitting this key leaves the stored address alone and sending it as `null` clears it."
     },
     "phone": {
      "type": "string",
      "description": "A contact number for this person, kept with their identity record and passed on when their identity is checked, 32 characters or fewer. On an update, omitting this key leaves the stored value alone and sending it as `null` clears it.",
      "example": "+2348012345678"
     },
     "email": {
      "type": "string",
      "format": "email",
      "description": "This person's own email address, separate from the account's `contact_email`, and used for correspondence about their verification rather than the account's. It must be a valid address or the request fails with `422`; on an update, omitting this key leaves the stored value alone and sending it as `null` clears it.",
      "example": "ada@example.com"
     },
     "id_number": {
      "type": "string",
      "description": "The person's government ID number. It is write-only: it is never echoed back, and the response reports `id_number_provided` instead. On an update, omitting this key leaves the stored number alone and sending it as `null` clears it.",
      "example": "22345678901"
     },
     "relationship": {
      "$ref": "#/components/schemas/PersonRelationship"
     }
    }
   },
   "UpdateAccountRequest": {
    "type": "object",
    "properties": {
     "configuration": {
      "type": "object",
      "additionalProperties": {
       "$ref": "#/components/schemas/AccountConfigurationOptions"
      },
      "description": "Personas to apply, and capabilities to request under them, the same nested shape as creation. Naming a persona here, with or without a capability nested under its `capabilities`, is what applies it if the account does not already have it: an account can start recipient-only and be given `merchant` later this way. Unlike creation, an omitted `capabilities` here never blanket-requests; it only applies the persona. A capability nested under the wrong persona for it is rejected with `400 capability_configuration_mismatch`. Only names set to `true` are acted on; any name set to `false` fails the whole request with `400 capability_unrequest_unsupported`. Capabilities the account already holds are unaffected, and an omitted map changes nothing."
     },
     "display_name": {
      "type": "string",
      "description": "The account's public name. Omit to leave it unchanged."
     },
     "contact_email": {
      "type": "string",
      "format": "email",
      "description": "Where onboarding correspondence for the account is sent. Omit to leave it unchanged."
     },
     "fields": {
      "type": "object",
      "additionalProperties": true,
      "description": "Requirement values, keyed by the field keys the account's requirements name: `persons`, `company.*`, `business_profile.*`, `payout_destination`, `tos_acceptance.*`. Omit to change nothing."
     },
     "balance_currencies": {
      "type": "object",
      "nullable": true,
      "additionalProperties": {
       "type": "boolean"
      },
      "description": "Which currencies the account holds, keyed by currency code. Holding a currency decides what the account settles in; a one-time checkout can be priced in any supported currency regardless. A recurring checkout is the exception and must be priced in a held currency, so set this before the account sells subscriptions in its own market. A new account holds only USD. Send `true` to add a currency and `false` to remove one. Omitthe field and nothing changes. USD is always held and cannot be removed. A currency Bachs cannot settle in is rejected with `400`.",
      "example": {
       "NGN": true
      }
     }
    },
    "description": "The one account write. Set contact details, request capabilities and satisfy requirement fields in a single call. Anything you leave out is unchanged."
   },
   "PayoutScheduleRequest": {
    "type": "object",
    "description": "Set when a currency pays out. Replaces the currency's schedule rather than patching it: a field you omit is cleared, not kept.",
    "required": [
     "interval"
    ],
    "properties": {
     "interval": {
      "type": "string",
      "enum": [
       "manual",
       "instant",
       "daily",
       "weekly",
       "monthly"
      ],
      "description": "How often this currency pays out.\n\n- `manual`: nothing is paid out automatically. The balance stays put until you call Create Payout.\n- `instant`: about a minute after funds settle, so several times on a busy day and not at all on a quiet one. Collections settling close together are paid out together, in one payout carrying one fee.\n- `daily`: once a day, at `anchor_hour_utc`.\n- `weekly`: once a week, on `weekly_anchor`, at `anchor_hour_utc`.\n- `monthly`: once a month, on `monthly_anchor`, at `anchor_hour_utc`.",
      "example": "daily"
     },
     "weekly_payout_days": {
      "type": "array",
      "nullable": true,
      "items": {
       "type": "string",
       "enum": [
        "monday",
        "tuesday",
        "wednesday",
        "thursday",
        "friday",
        "saturday",
        "sunday"
       ]
      },
      "description": "Weekdays a weekly payout lands on. Listing more than one means more than one payout a week: `[\"monday\", \"thursday\"]` pays twice. Defaults to `[\"monday\"]`. Sending it on any other interval is rejected rather than ignored, so a schedule never quietly loses the days you asked for.",
      "example": [
       "monday",
       "thursday"
      ]
     },
     "monthly_payout_days": {
      "type": "array",
      "nullable": true,
      "items": {
       "type": "integer",
       "minimum": 1,
       "maximum": 31
      },
      "description": "Days of the month a monthly payout lands on, each `1` to `31`. Listing more than one means more than one payout a month. 29, 30 and 31 land on the last day of a shorter month, so `[31]` pays on the 31st of January and the 28th of February. Defaults to `[1]`. Sending it on any other interval is rejected.",
      "example": [
       1,
       15
      ]
     },
     "anchor_hour_utc": {
      "type": "integer",
      "nullable": true,
      "minimum": 0,
      "maximum": 23,
      "description": "The UTC hour to run at, `0` to `23`. Defaults to `10`. Ignored by `manual` and `instant`.",
      "example": 9
     },
     "payout_currency": {
      "type": "string",
      "nullable": true,
      "description": "The currency to deliver the money in, in ISO 4217 format. Defaults to the balance currency. Setting it to something else converts each run at the rate of the day it runs, and is available out of USD and stablecoin balances only. Converting out of a local settlement currency is rejected here rather than at run time.",
      "example": "NGN"
     },
     "minimum_amount": {
      "type": "string",
      "nullable": true,
      "description": "A floor for a run, as a decimal string (e.g. \"5000.00\") in the balance currency. A run whose eligible total is below it pays nothing and the money rolls into the next run. Omit for no floor.",
      "example": "5000.00"
     }
    }
   },
   "PayoutScheduleResponse": {
    "type": "object",
    "description": "The payout schedule for one currency of one account.",
    "properties": {
     "currency": {
      "type": "string",
      "description": "The balance currency this schedule governs, in ISO 4217 format. Each currency is scheduled independently.",
      "example": "NGN"
     },
     "payout_currency": {
      "type": "string",
      "description": "The currency the money is delivered in. Equal to `currency` unless the schedule converts, in which case each run is quoted at the rate of the day it runs.",
      "example": "NGN"
     },
     "interval": {
      "type": "string",
      "enum": [
       "manual",
       "instant",
       "daily",
       "weekly",
       "monthly"
      ],
      "description": "How often this currency pays out.\n\n- `manual`: nothing is paid out automatically. The balance stays put until you call Create Payout.\n- `instant`: about a minute after funds settle, so several times on a busy day and not at all on a quiet one. Collections settling close together are paid out together, in one payout carrying one fee.\n- `daily`: once a day, at `anchor_hour_utc`.\n- `weekly`: once a week, on `weekly_anchor`, at `anchor_hour_utc`.\n- `monthly`: once a month, on `monthly_anchor`, at `anchor_hour_utc`.",
      "example": "daily"
     },
     "weekly_payout_days": {
      "type": "array",
      "nullable": true,
      "items": {
       "type": "string",
       "enum": [
        "monday",
        "tuesday",
        "wednesday",
        "thursday",
        "friday",
        "saturday",
        "sunday"
       ]
      },
      "description": "Weekdays a weekly payout lands on. Listing more than one means more than one payout a week: `[\"monday\", \"thursday\"]` pays twice. Null on every other interval, because nothing else reads it.",
      "example": [
       "monday",
       "thursday"
      ]
     },
     "monthly_payout_days": {
      "type": "array",
      "nullable": true,
      "items": {
       "type": "integer",
       "minimum": 1,
       "maximum": 31
      },
      "description": "Days of the month a monthly payout lands on, each `1` to `31`. Listing more than one means more than one payout a month. 29, 30 and 31 land on the last day of a shorter month, so `[31]` pays on the 31st of January and the 28th of February. Null on every other interval.",
      "example": [
       1,
       15
      ]
     },
     "anchor_hour_utc": {
      "type": "integer",
      "nullable": true,
      "minimum": 0,
      "maximum": 23,
      "description": "The UTC hour a scheduled run happens, `0` to `23`. Defaults to `10`. Null on `manual` and `instant`, which have no schedule.",
      "example": 9
     },
     "minimum_amount": {
      "type": "string",
      "nullable": true,
      "description": "The floor a run has to reach before it pays anything, as a decimal string in `currency`. A run below it pays nothing and the money rolls into the next run. Null means no floor.",
      "example": "5000.00"
     },
     "next_run_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "When the next scheduled run is due, in ISO 8601. Always null on `manual` and `instant`: one pays out nothing and the other reacts to funds settling rather than to a clock, so neither has a next run to show.",
      "example": "2026-08-13T09:00:00.000Z"
     },
     "last_run_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true,
      "description": "When a run last happened, in ISO 8601, whether or not it moved money. Null until the first run.",
      "example": "2026-08-12T09:00:00.000Z"
     },
     "last_withdrawal_id": {
      "type": "string",
      "nullable": true,
      "description": "The payout created by the last run that moved money. Read it with Get Payout. Null until a run has paid out.",
      "example": "pay_4Xr9dLc0mNv7Kq2B"
     },
     "disabled_reason": {
      "type": "string",
      "nullable": true,
      "description": "Why the currency was set back to `manual` by itself, including the error from the run that tripped it. Null when that never happened.",
      "example": "Auto-payout paused after 3 consecutive failures. Last error: destination rejected in review"
     }
    }
   },
   "PayoutSettingsRequest": {
    "type": "object",
    "description": "The payout schedule to set, one call at a time.",
    "properties": {
     "schedule_by_currency": {
      "type": "object",
      "nullable": true,
      "additionalProperties": {
       "$ref": "#/components/schemas/PayoutScheduleRequest"
      },
      "description": "Payout schedules to set, keyed by the balance currency each one governs. A currency you leave out keeps the schedule it has, so one call changes NGN without touching USD."
     }
    }
   },
   "PayoutSettingsResponse": {
    "type": "object",
    "properties": {
     "schedule_by_currency": {
      "type": "object",
      "additionalProperties": {
       "$ref": "#/components/schemas/PayoutScheduleResponse"
      },
      "description": "Payout schedules, keyed by the balance currency each one governs. A currency with no schedule is absent rather than present and empty, so you can tell \"never configured\" from \"pays out weekly\"."
     }
    }
   },
   "WebhookEndpointListResponse": {
    "type": "object",
    "properties": {
     "items": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/WebhookEndpoint"
      },
      "description": "The webhook endpoints registered on this account, newest first. One page of them, bounded by `limit`."
     },
     "pagination": {
      "allOf": [
       {
        "$ref": "#/components/schemas/PaginationResponse"
       }
      ],
      "description": "Where this page sits in the full set, and the cursor for the next one. See [Pagination](/guides/pagination)."
     }
    },
    "required": [
     "items",
     "pagination"
    ]
   },
   "CreateChargeRequest": {
    "type": "object",
    "required": [
     "customer",
     "amount",
     "currency"
    ],
    "properties": {
     "customer": {
      "type": "string",
      "description": "The customer to charge, by their `cust_` id. They must already have a saved card, or the request is refused with `NO_SAVED_PAYMENT_METHOD`."
     },
     "payment_method": {
      "type": "string",
      "nullable": true,
      "description": "The saved card to charge, by its `pm_` id. Omit to charge the customer's default saved card, which is the first card they saved. A card belonging to a different customer is refused with `SAVED_PAYMENT_METHOD_NOT_FOUND`."
     },
     "amount": {
      "type": "string",
      "description": "The amount to collect, as a decimal string (for example `\"29.00\"`). Must be greater than zero. This is the amount before the processing fee: when your account passes the fee to the customer, the card is charged more than this and the response `amount` shows the total."
     },
     "currency": {
      "type": "string",
      "description": "The currency of `amount`, in [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) format (for example `USD`). Your account must be able to collect card payments in this currency, or the request is refused with `PAYMENT_METHOD_NOT_ENABLED`."
     },
     "description": {
      "type": "string",
      "nullable": true,
      "maxLength": 255,
      "description": "What the charge is for. Returned as `narration` on the payment, and shown on your dashboard."
     },
     "reference": {
      "type": "string",
      "nullable": true,
      "maxLength": 128,
      "description": "Your own identifier for this charge, returned unchanged on the payment so you can match it to your records."
     },
     "metadata": {
      "type": "object",
      "nullable": true,
      "additionalProperties": true,
      "description": "Key-value pairs you attach to the charge and get back on the payment and its webhooks."
     }
    }
   },
   "FeeInfo": {
    "type": "object",
    "description": "The Bachs processing fee on a payment, in the currency it was charged in. Taken from the payment with no conversion applied, so it is the figure to reconcile against when the payment was not collected in USD.",
    "properties": {
     "amount": {
      "type": "string",
      "description": "The fee, as a decimal string in `currency`.",
      "example": "8.73"
     },
     "currency": {
      "type": "string",
      "description": "The currency the fee was charged in, as an [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) code. This is the currency the payment was collected in, which is not always the currency it settles to.",
      "example": "USD"
     }
    },
    "required": [
     "amount",
     "currency"
    ]
   }
  },
  "responses": {
   "BadRequest": {
    "description": "Bad Request - Validation errors or invalid request format. Check the `details` object for field-specific validation errors. Common causes: missing required fields, invalid data types, values outside allowed ranges, or invalid formats.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "Invalid request parameters",
       "error_code": "VALIDATION_ERROR",
       "errors": [
        {
         "field": "amount",
         "message": "Amount must be a positive decimal string",
         "type": "value_error"
        }
       ]
      }
     }
    },
    "headers": {
     "X-RateLimit-Limit": {
      "description": "Maximum number of requests allowed per minute",
      "schema": {
       "type": "integer",
       "example": 100
      }
     },
     "X-RateLimit-Remaining": {
      "description": "Number of requests remaining in the current window",
      "schema": {
       "type": "integer",
       "example": 95
      }
     },
     "X-RateLimit-Reset": {
      "description": "Unix timestamp when the rate limit window resets",
      "schema": {
       "type": "integer",
       "example": 1706102400
      }
     }
    }
   },
   "Unauthorized": {
    "description": "Unauthorized - Invalid, missing, or expired API key. Verify your API key is correctly formatted and included in the Authorization header as `Bearer sk_sandbox_...` or `Bearer sk_live_...`. Check that your key hasn't been revoked.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "Invalid API key",
       "error_code": "UNAUTHORIZED"
      }
     }
    },
    "headers": {
     "X-RateLimit-Limit": {
      "description": "Maximum number of requests allowed per minute",
      "schema": {
       "type": "integer",
       "example": 100
      }
     },
     "X-RateLimit-Remaining": {
      "description": "Number of requests remaining in the current window",
      "schema": {
       "type": "integer",
       "example": 95
      }
     },
     "X-RateLimit-Reset": {
      "description": "Unix timestamp when the rate limit window resets",
      "schema": {
       "type": "integer",
       "example": 1706102400
      }
     }
    }
   },
   "Forbidden": {
    "description": "Forbidden - API key does not have permission for the requested resource. Verify you're using the correct account's API key and that you're not trying to access another account's data.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "API key does not have permission for this operation",
       "error_code": "FORBIDDEN"
      }
     }
    },
    "headers": {
     "X-RateLimit-Limit": {
      "description": "Maximum number of requests allowed per minute",
      "schema": {
       "type": "integer",
       "example": 100
      }
     },
     "X-RateLimit-Remaining": {
      "description": "Number of requests remaining in the current window",
      "schema": {
       "type": "integer",
       "example": 95
      }
     },
     "X-RateLimit-Reset": {
      "description": "Unix timestamp when the rate limit window resets",
      "schema": {
       "type": "integer",
       "example": 1706102400
      }
     }
    }
   },
   "NotFound": {
    "description": "Not Found - The requested resource does not exist. Verify the resource ID is correct and that it belongs to your account.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "Resource not found",
       "error_code": "NOT_FOUND"
      }
     }
    },
    "headers": {
     "X-RateLimit-Limit": {
      "description": "Maximum number of requests allowed per minute",
      "schema": {
       "type": "integer",
       "example": 100
      }
     },
     "X-RateLimit-Remaining": {
      "description": "Number of requests remaining in the current window",
      "schema": {
       "type": "integer",
       "example": 95
      }
     },
     "X-RateLimit-Reset": {
      "description": "Unix timestamp when the rate limit window resets",
      "schema": {
       "type": "integer",
       "example": 1706102400
      }
     }
    }
   },
   "Conflict": {
    "description": "Conflict - Duplicate request detected (idempotency). This occurs when the same request is made multiple times with the same idempotency key. The original request's response is returned.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "Duplicate request detected",
       "error_code": "CONFLICT"
      }
     }
    },
    "headers": {
     "X-RateLimit-Limit": {
      "description": "Maximum number of requests allowed per minute",
      "schema": {
       "type": "integer",
       "example": 100
      }
     },
     "X-RateLimit-Remaining": {
      "description": "Number of requests remaining in the current window",
      "schema": {
       "type": "integer",
       "example": 95
      }
     },
     "X-RateLimit-Reset": {
      "description": "Unix timestamp when the rate limit window resets",
      "schema": {
       "type": "integer",
       "example": 1706102400
      }
     }
    }
   },
   "TooManyRequests": {
    "description": "Too Many Requests - Rate limit exceeded. Standard tier allows 100 requests per minute per API key. Wait a few seconds before retrying. Check X-RateLimit-Reset header for when the window resets.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "Rate limit exceeded. Please retry after a few seconds.",
       "error_code": "TOO_MANY_REQUESTS"
      }
     }
    },
    "headers": {
     "X-RateLimit-Limit": {
      "description": "Maximum number of requests allowed per minute",
      "schema": {
       "type": "integer",
       "example": 100
      }
     },
     "X-RateLimit-Remaining": {
      "description": "Number of requests remaining in the current window (will be 0)",
      "schema": {
       "type": "integer",
       "example": 0
      }
     },
     "X-RateLimit-Reset": {
      "description": "Unix timestamp when the rate limit window resets",
      "schema": {
       "type": "integer",
       "example": 1706102400
      }
     },
     "Retry-After": {
      "description": "Number of seconds to wait before retrying",
      "schema": {
       "type": "integer",
       "example": 30
      }
     }
    }
   },
   "InternalServerError": {
    "description": "Internal Server Error - An unexpected error occurred while processing the request. Retry with exponential backoff. If the issue persists, contact support with your request context.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "An unexpected error occurred. Please try again later.",
       "error_code": "INTERNAL_SERVER_ERROR"
      }
     }
    },
    "headers": {
     "X-RateLimit-Limit": {
      "description": "Maximum number of requests allowed per minute",
      "schema": {
       "type": "integer",
       "example": 100
      }
     },
     "X-RateLimit-Remaining": {
      "description": "Number of requests remaining in the current window",
      "schema": {
       "type": "integer",
       "example": 95
      }
     },
     "X-RateLimit-Reset": {
      "description": "Unix timestamp when the rate limit window resets",
      "schema": {
       "type": "integer",
       "example": 1706102400
      }
     }
    }
   },
   "RequirementValidationFailed": {
    "description": "One or more submitted fields failed validation. `missing_fields` names every field key that has to be corrected or supplied, and `missing_documents` names the documents still outstanding. Fix the named keys and resubmit; nothing from a rejected submission is persisted.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "Submission has missing or invalid required fields",
       "error_code": "VALIDATION_FAILED",
       "missing_fields": [
        "company.registration_number"
       ],
       "missing_documents": []
      }
     }
    }
   },
   "ValidationError": {
    "description": "Validation Error - one or more fields failed validation. Inspect `errors[]` for the field, the message, and the failure type, correct them, and retry.",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "detail": "Validation failed for one or more fields",
       "error_code": "VALIDATION_ERROR",
       "doc_url": "https://docs.bachs.io/api-reference/error-reference#general",
       "errors": [
        {
         "field": "name",
         "message": "This field is required",
         "type": "missing"
        }
       ]
      }
     }
    },
    "headers": {
     "X-RateLimit-Limit": {
      "description": "Maximum number of requests allowed per minute",
      "schema": {
       "type": "integer",
       "example": 100
      }
     },
     "X-RateLimit-Remaining": {
      "description": "Number of requests remaining in the current window",
      "schema": {
       "type": "integer",
       "example": 95
      }
     },
     "X-RateLimit-Reset": {
      "description": "Unix timestamp when the rate limit window resets",
      "schema": {
       "type": "integer",
       "example": 1706102400
      }
     }
    }
   }
  },
  "headers": {
   "X-Account-Id": {
    "description": "Optional header to target an account you own. Use the parent platform's API key.",
    "schema": {
     "type": "string"
    }
   }
  }
 }
}
