{
 "openapi": "3.1.0",
 "info": {
  "title": "Biftpay API",
  "version": "0.1.0",
  "description": "Accept payments, manage balances and pay out in Nigeria. Amounts are integers in the minor unit (kobo, cents). Every POST takes an Idempotency-Key header. Test keys (bp_test_) and live keys (bp_live_) see separate data. Lists are newest first and page with starting_after."
 },
 "servers": [],
 "security": [
  {
   "apiKey": []
  }
 ],
 "tags": [
  {
   "name": "Payment intents"
  },
  {
   "name": "Balance"
  },
  {
   "name": "Payouts"
  },
  {
   "name": "Refunds"
  },
  {
   "name": "Webhooks"
  },
  {
   "name": "Brands"
  },
  {
   "name": "Customers"
  },
  {
   "name": "Payment links"
  },
  {
   "name": "Disputes"
  },
  {
   "name": "Invoices"
  },
  {
   "name": "Virtual accounts"
  },
  {
   "name": "Subscriptions"
  },
  {
   "name": "Test helpers"
  }
 ],
 "paths": {
  "/v1/payment_intents": {
   "post": {
    "tags": [
     "Payment intents"
    ],
    "operationId": "createPaymentIntent",
    "x-status": "live",
    "summary": "Create a payment intent",
    "description": "Fees and VAT are calculated from the merchant's pricing and fixed on the intent at creation.",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreatePaymentIntent"
       },
       "example": {
        "amount": 1000000,
        "currency": "NGN",
        "reference": "order-10293",
        "customer_email": "ada@example.com"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Created",
      "headers": {
       "Idempotent-Replayed": {
        "$ref": "#/components/headers/IdempotentReplayed"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentIntent"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "422": {
      "$ref": "#/components/responses/IdempotencyConflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "get": {
    "tags": [
     "Payment intents"
    ],
    "operationId": "listPaymentIntents",
    "x-status": "live",
    "summary": "List payment intents",
    "parameters": [
     {
      "$ref": "#/components/parameters/Limit"
     },
     {
      "$ref": "#/components/parameters/StartingAfter"
     },
     {
      "name": "customer",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     },
     {
      "name": "status",
      "in": "query",
      "schema": {
       "$ref": "#/components/schemas/PaymentIntentStatus"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "A page of payment intents",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentIntentList"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payment_intents/{id}": {
   "get": {
    "tags": [
     "Payment intents"
    ],
    "operationId": "getPaymentIntent",
    "x-status": "live",
    "summary": "Retrieve a payment intent",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "The payment intent",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentIntent"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payment_intents/{id}/cancel": {
   "post": {
    "tags": [
     "Payment intents"
    ],
    "operationId": "cancelPaymentIntent",
    "x-status": "live",
    "summary": "Cancel a payment intent",
    "description": "Only an unpaid intent (status `created`, `failed` or `abandoned`) can be canceled.",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "The canceled payment intent",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentIntent"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payment_intents/{id}/charge_attempts": {
   "get": {
    "tags": [
     "Payment intents"
    ],
    "operationId": "listChargeAttempts",
    "x-status": "live",
    "summary": "Every try behind a payment, in order",
    "description": "Each card or transfer try, in order: for example a declined card followed by one that worked.",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "Attempts",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/ChargeAttempt"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/balance": {
   "get": {
    "tags": [
     "Balance"
    ],
    "operationId": "getBalance",
    "x-status": "live",
    "summary": "Retrieve balances",
    "description": "Read straight from the ledger. One entry per currency in each bucket. Each brand\nholds its own money; without `brand` this is the whole business (the sum of its brands).\n",
    "parameters": [
     {
      "name": "brand",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      },
      "description": "One brand's own money (default: the whole business)"
     }
    ],
    "responses": {
     "200": {
      "description": "Current balances",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Balance"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/balance_transactions": {
   "get": {
    "tags": [
     "Balance"
    ],
    "operationId": "listBalanceTransactions",
    "x-status": "live",
    "summary": "Every movement on the merchant's balances, newest first",
    "description": "One row per ledger line on the merchant's accounts. `amount` is signed in the\nmerchant's terms: positive adds to `bucket`, negative takes from it; `balance_after`\nis that bucket's balance after the line. Payment lines carry `gross` and `fee`\n(fee plus VAT). Lines of one entry share `type` and `created_at`. Paginate with\n`starting_after=<id>`.\n",
    "parameters": [
     {
      "$ref": "#/components/parameters/Limit"
     },
     {
      "name": "starting_after",
      "in": "query",
      "schema": {
       "type": "string",
       "pattern": "^[0-9]+$"
      }
     },
     {
      "name": "brand",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      },
      "description": "One brand's own money (default: the whole business)"
     },
     {
      "name": "currency",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "NGN",
        "USD"
       ]
      }
     },
     {
      "name": "bucket",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "available",
        "pending",
        "reserve",
        "payout_in_flight",
        "refund_in_flight",
        "dispute_hold"
       ]
      }
     },
     {
      "name": "type",
      "in": "query",
      "required": false,
      "description": "Comma-separated: payments, releases, payouts, refunds, disputes, conversions (corrections included).",
      "schema": {
       "type": "string",
       "example": "payments,payouts"
      }
     },
     {
      "name": "from",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "Inclusive, Lagos time"
     },
     {
      "name": "to",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "Inclusive, Lagos time"
     }
    ],
    "responses": {
     "200": {
      "description": "A page of balance transactions",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BalanceTransactionList"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/balance_transactions/export": {
   "get": {
    "tags": [
     "Balance"
    ],
    "operationId": "exportBalanceTransactions",
    "x-status": "live",
    "summary": "The statement as CSV (up to 20,000 lines; narrow the dates for more)",
    "description": "Same filters as the list. The CSV comes in `data`, for a dashboard to save as `file_name`.",
    "parameters": [
     {
      "name": "brand",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      },
      "description": "One brand's own money (default: the whole business)"
     },
     {
      "name": "currency",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "NGN",
        "USD"
       ]
      }
     },
     {
      "name": "bucket",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "available",
        "pending",
        "reserve",
        "payout_in_flight",
        "refund_in_flight",
        "dispute_hold"
       ]
      }
     },
     {
      "name": "type",
      "in": "query",
      "required": false,
      "description": "Comma-separated: payments, releases, payouts, refunds, disputes, conversions (corrections included).",
      "schema": {
       "type": "string",
       "example": "payments,payouts"
      }
     },
     {
      "name": "from",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "Inclusive, Lagos time"
     },
     {
      "name": "to",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "date"
      },
      "description": "Inclusive, Lagos time"
     }
    ],
    "responses": {
     "200": {
      "description": "The statement",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "file_name",
          "content_type",
          "rows",
          "truncated",
          "data"
         ],
         "properties": {
          "object": {
           "const": "statement_export"
          },
          "file_name": {
           "type": "string",
           "example": "biftpay-statement-live-NGN-2026-09-01_to_2026-09-30.csv"
          },
          "content_type": {
           "const": "text/csv"
          },
          "rows": {
           "type": "integer"
          },
          "truncated": {
           "type": "boolean",
           "description": "More lines matched than one export holds."
          },
          "data": {
           "type": "string",
           "description": "CSV text"
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/reserve": {
   "get": {
    "tags": [
     "Balance"
    ],
    "operationId": "getReserve",
    "x-status": "live",
    "summary": "Your rolling reserve - terms, what's held, and when it's released",
    "description": "A rolling reserve holds a share of each payment for a set time against chargebacks.\n`terms` is null when none applies. Held money is released to available automatically,\non the dates in `releases` (Lagos days).\n",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "livemode",
          "terms",
          "held",
          "releases"
         ],
         "properties": {
          "object": {
           "const": "reserve"
          },
          "livemode": {
           "type": "boolean"
          },
          "terms": {
           "type": [
            "object",
            "null"
           ],
           "required": [
            "percent_bps",
            "days",
            "reason",
            "reason_text",
            "note",
            "since"
           ],
           "properties": {
            "percent_bps": {
             "type": "integer",
             "example": 1000
            },
            "days": {
             "type": "integer",
             "example": 30
            },
            "reason": {
             "type": [
              "string",
              "null"
             ]
            },
            "reason_text": {
             "type": [
              "string",
              "null"
             ],
             "description": "The reason in plain words."
            },
            "note": {
             "type": [
              "string",
              "null"
             ]
            },
            "since": {
             "type": [
              "string",
              "null"
             ],
             "format": "date-time"
            }
           }
          },
          "held": {
           "type": "array",
           "items": {
            "type": "object",
            "required": [
             "currency",
             "amount",
             "payments",
             "next_release_at"
            ],
            "properties": {
             "currency": {
              "type": "string"
             },
             "amount": {
              "$ref": "#/components/schemas/Amount"
             },
             "payments": {
              "type": "integer"
             },
             "next_release_at": {
              "type": [
               "string",
               "null"
              ],
              "format": "date-time"
             }
            }
           }
          },
          "releases": {
           "type": "array",
           "items": {
            "type": "object",
            "required": [
             "date",
             "currency",
             "amount"
            ],
            "properties": {
             "date": {
              "type": "string",
              "format": "date"
             },
             "currency": {
              "type": "string"
             },
             "amount": {
              "$ref": "#/components/schemas/Amount"
             }
            }
           }
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/fx": {
   "get": {
    "tags": [
     "Balance"
    ],
    "operationId": "getFx",
    "x-status": "live",
    "summary": "Biftpay's dollar rate, the dollars available to convert, and (with usd_amount) the naira they'd give",
    "parameters": [
     {
      "name": "brand",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     },
     {
      "name": "usd_amount",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1
      },
      "description": "Cents."
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FxPreview"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/fx/conversions": {
   "get": {
    "tags": [
     "Balance"
    ],
    "operationId": "listFxConversionsMerchant",
    "x-status": "live",
    "summary": "Your dollar-to-naira conversions, newest first",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data",
          "has_more"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/FxConversion"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "tags": [
     "Balance"
    ],
    "operationId": "convertUsd",
    "x-status": "live",
    "summary": "Convert dollars to naira at the rate you were shown",
    "description": "`rate_id` is the rate from GET /v1/fx. If Biftpay has published a new rate since, nothing\nconverts and the error says the new rate (`rate_changed`). Naira is rounded down to the kobo.\n",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "usd_amount",
         "rate_id"
        ],
        "properties": {
         "usd_amount": {
          "type": "integer",
          "minimum": 1,
          "description": "Cents."
         },
         "rate_id": {
          "type": "string",
          "format": "uuid"
         },
         "brand": {
          "type": "string",
          "format": "uuid"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Converted",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FxConversion"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/bank_accounts": {
   "post": {
    "tags": [
     "Payouts"
    ],
    "operationId": "createBankAccount",
    "x-status": "live",
    "summary": "Register a payout destination",
    "description": "The account is checked with the bank (name enquiry) before it is saved, and the\naccount name the bank returns is what is stored and shown. Adding the same\naccount again returns the existing one. In test mode, account numbers ending in\n`0000` fail name enquiry.\n",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateBankAccount"
       },
       "example": {
        "bank_code": "999",
        "account_number": "0123456789"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "The verified bank account",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/BankAccount"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "get": {
    "tags": [
     "Payouts"
    ],
    "operationId": "listBankAccounts",
    "x-status": "live",
    "summary": "List payout destinations",
    "responses": {
     "200": {
      "description": "Registered bank accounts",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data",
          "has_more"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/BankAccount"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payouts": {
   "post": {
    "tags": [
     "Payouts"
    ],
    "operationId": "createPayout",
    "x-status": "live",
    "summary": "Pay out to a registered bank account",
    "description": "Moves amount + fee + VAT from `available` to `payout_in_flight` in the same step\nthat records the payout, so a short balance fails with `409 insufficient_funds`\nand nothing is written. Payouts at or above the merchant's approval threshold\nwait for Biftpay's review (`awaiting_approval`). The outcome is settled\nonly from the bank's status query: `paid`, or `failed` with the money returned\nto `available`.\n\nIn test mode, account numbers ending in `9999` fail after sending, `7777` are\nrejected by the provider, and `8888` stay `processing`.\n",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreatePayout"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Created",
      "headers": {
       "Idempotent-Replayed": {
        "$ref": "#/components/headers/IdempotentReplayed"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Payout"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "422": {
      "$ref": "#/components/responses/IdempotencyConflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "get": {
    "tags": [
     "Payouts"
    ],
    "operationId": "listPayouts",
    "x-status": "live",
    "summary": "List payouts",
    "parameters": [
     {
      "$ref": "#/components/parameters/Limit"
     },
     {
      "$ref": "#/components/parameters/StartingAfter"
     }
    ],
    "responses": {
     "200": {
      "description": "A page of payouts",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PayoutList"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payouts/{id}": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "operationId": "getPayout",
    "x-status": "live",
    "summary": "Retrieve a payout",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "The payout",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Payout"
        }
       }
      }
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payouts/{id}/cancel": {
   "post": {
    "tags": [
     "Payouts"
    ],
    "operationId": "cancelPayout",
    "x-status": "live",
    "summary": "Cancel a payout before it is sent",
    "description": "Only `awaiting_approval` and `queued` payouts can be canceled. The held money returns to `available`.",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "The canceled payout",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Payout"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payouts/quote": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "operationId": "quotePayout",
    "x-status": "live",
    "summary": "What a payout would cost, and whether the balance covers it",
    "description": "The fee and VAT go on top of the amount and come from the same available balance (the\nbrand's, with `brand`). `max_amount` is the most that can be paid out now. Creating the\npayout checks again.\n",
    "parameters": [
     {
      "name": "amount",
      "in": "query",
      "required": true,
      "schema": {
       "type": "integer",
       "minimum": 1
      }
     },
     {
      "name": "currency",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "NGN"
       ]
      }
     },
     {
      "name": "brand",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The quote",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "currency",
          "amount",
          "fee",
          "vat",
          "total_debited",
          "available",
          "max_amount",
          "max_reason",
          "sufficient",
          "within_limits",
          "limits"
         ],
         "properties": {
          "object": {
           "const": "payout_quote"
          },
          "currency": {
           "type": "string",
           "enum": [
            "NGN"
           ]
          },
          "amount": {
           "$ref": "#/components/schemas/Amount"
          },
          "fee": {
           "$ref": "#/components/schemas/Amount"
          },
          "vat": {
           "$ref": "#/components/schemas/Amount"
          },
          "total_debited": {
           "$ref": "#/components/schemas/Amount"
          },
          "available": {
           "$ref": "#/components/schemas/Amount"
          },
          "max_amount": {
           "$ref": "#/components/schemas/Amount"
          },
          "max_reason": {
           "type": "string",
           "enum": [
            "balance",
            "per_payout",
            "daily"
           ],
           "description": "What holds max_amount where it is."
          },
          "sufficient": {
           "type": "boolean",
           "description": "The balance covers amount + fee + VAT."
          },
          "within_limits": {
           "type": "boolean"
          },
          "limits": {
           "type": "object",
           "required": [
            "tier",
            "custom",
            "per_payout",
            "daily",
            "used_today"
           ],
           "properties": {
            "tier": {
             "type": "string"
            },
            "custom": {
             "type": "boolean"
            },
            "per_payout": {
             "type": "integer"
            },
            "daily": {
             "type": "integer"
            },
            "used_today": {
             "type": "integer"
            }
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/usdt": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "operationId": "getUsdt",
    "x-status": "live",
    "summary": "USDT settlement: whether it's on, Biftpay's rules, your wallets and the one automatic settlement uses",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "enabled",
          "settle_wallet",
          "settings",
          "wallets"
         ],
         "properties": {
          "object": {
           "const": "usdt"
          },
          "enabled": {
           "type": "boolean"
          },
          "settle_wallet": {
           "type": [
            "string",
            "null"
           ]
          },
          "settings": {
           "$ref": "#/components/schemas/UsdtSettings"
          },
          "wallets": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/CryptoWallet"
           }
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/usdt/preview": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "operationId": "previewUsdtPayout",
    "x-status": "live",
    "summary": "Before sending: dollars available, the fee, and the USDT the wallet should receive",
    "parameters": [
     {
      "name": "usd_amount",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1
      },
      "description": "Cents."
     },
     {
      "name": "brand",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/UsdtPreview"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/usdt/payouts": {
   "get": {
    "tags": [
     "Payouts"
    ],
    "operationId": "listUsdtPayouts",
    "x-status": "live",
    "summary": "Your USDT payouts, newest first",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data",
          "has_more"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/CryptoPayout"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "tags": [
     "Payouts"
    ],
    "operationId": "createUsdtPayout",
    "x-status": "live",
    "summary": "Send dollars as USDT to one of your wallets (added and cleared in the dashboard)",
    "description": "The amount (cents) leaves your USD balance; Biftpay's fee and VAT come out of it and the\npartner sends the rest as USDT, 1 USDT per dollar. Held until the partner confirms, returned\nif it fails.\n",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "usd_amount",
         "wallet"
        ],
        "properties": {
         "usd_amount": {
          "type": "integer",
          "minimum": 1
         },
         "wallet": {
          "type": "string",
          "format": "uuid"
         },
         "brand": {
          "type": "string",
          "format": "uuid"
         },
         "otp": {
          "$ref": "#/components/schemas/OtpProof"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Queued",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CryptoPayout"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/refunds": {
   "post": {
    "tags": [
     "Refunds"
    ],
    "operationId": "createRefund",
    "x-status": "live",
    "summary": "Refund a successful payment, in full or in part",
    "description": "Sent back through the provider that charged the customer. The amount is held from\nthe merchant's balance (`pending` if not yet released, else `available`) into\n`refund_in_flight`, then settled when the provider confirms or returned if it fails.\nProcessing fees aren't returned. Omit `amount` to refund what's left.\n\nA payment with an open dispute can't be refunded (409 `payment_disputed`): the\nchargeback already returns the money, so answer the dispute instead. What a lost\ndispute returned counts towards the amount already refunded.\n\nIn test mode, amounts ending in 13 kobo are rejected and ending in 17 stay pending.\n",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateRefund"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Refund"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "get": {
    "tags": [
     "Refunds"
    ],
    "operationId": "listRefunds",
    "x-status": "live",
    "summary": "List refunds",
    "parameters": [
     {
      "$ref": "#/components/parameters/Limit"
     },
     {
      "name": "payment_intent",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Refunds, newest first",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data",
          "has_more"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Refund"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/refunds/{id}": {
   "get": {
    "tags": [
     "Refunds"
    ],
    "operationId": "getRefund",
    "x-status": "live",
    "summary": "Retrieve a refund",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "The refund",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Refund"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/webhook_endpoints": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "operationId": "createWebhookEndpoint",
    "x-status": "live",
    "summary": "Register a webhook endpoint",
    "description": "The signing `secret` is returned once, here. URLs must be https with a public\nhostname. Each delivery has headers `Biftpay-Event-Id`, `Biftpay-Timestamp` and\n`Biftpay-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<event id>.<body>\">`.\nRecompute it with the secret, compare in constant time and reject anything older\nthan 5 minutes. Failed deliveries retry after 1m, 5m, 30m, 2h, 6h and 12h.\n",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "url"
        ],
        "properties": {
         "url": {
          "type": "string",
          "format": "uri",
          "example": "https://merchant.example.com/biftpay/webhooks"
         },
         "events": {
          "type": "array",
          "description": "Omit or leave empty for every event type.",
          "items": {
           "$ref": "#/components/schemas/EventType"
          }
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Created",
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "$ref": "#/components/schemas/WebhookEndpoint"
          },
          {
           "type": "object",
           "required": [
            "secret"
           ],
           "properties": {
            "secret": {
             "type": "string",
             "example": "whsec_3jR8kQ2nVt9Lm4Xp7Wc1Zy6Hb0Gf5Sd"
            }
           }
          }
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "get": {
    "tags": [
     "Webhooks"
    ],
    "operationId": "listWebhookEndpoints",
    "x-status": "live",
    "summary": "List webhook endpoints for the current mode",
    "responses": {
     "200": {
      "description": "Webhook endpoints",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data",
          "has_more"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/WebhookEndpoint"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/webhook_endpoints/{id}/disable": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "operationId": "disableWebhookEndpoint",
    "x-status": "live",
    "summary": "Stop sending to an endpoint",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "The disabled endpoint",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEndpoint"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/webhook_endpoints/{id}/enable": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "operationId": "enableWebhookEndpoint",
    "x-status": "live",
    "summary": "Start sending to a disabled endpoint again",
    "description": "New events go to it from now. Send ones it missed with POST /v1/events/{id}/redeliver.",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "The enabled endpoint",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/WebhookEndpoint"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/webhook_endpoints/{id}/delete": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "operationId": "deleteWebhookEndpoint",
    "x-status": "live",
    "summary": "Delete an endpoint",
    "description": "Nothing more is sent to it, including deliveries still waiting, and it leaves the list.\nIts past deliveries stay in the event history. This can't be undone; add the URL again\nto get a new endpoint (with a new signing secret).\n",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "Deleted",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "id",
          "object",
          "deleted"
         ],
         "properties": {
          "id": {
           "type": "string"
          },
          "object": {
           "const": "webhook_endpoint"
          },
          "deleted": {
           "const": true
          }
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/events": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "operationId": "listEvents",
    "x-status": "live",
    "summary": "List events and their delivery status",
    "parameters": [
     {
      "$ref": "#/components/parameters/Limit"
     },
     {
      "$ref": "#/components/parameters/StartingAfter"
     },
     {
      "name": "type",
      "in": "query",
      "schema": {
       "$ref": "#/components/schemas/EventType"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "A page of events",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/EventList"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/events/{id}/redeliver": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "operationId": "redeliverEvent",
    "x-status": "live",
    "summary": "Send an event again to its endpoints",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "How many deliveries were queued",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "object": {
           "const": "event_redelivery"
          },
          "event_id": {
           "type": "string"
          },
          "queued": {
           "type": "integer"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/test_helpers/payment_intents/{id}/succeed": {
   "post": {
    "tags": [
     "Test helpers"
    ],
    "operationId": "testSucceedPaymentIntent",
    "x-status": "live",
    "summary": "Simulate a successful payment (test keys only)",
    "description": "Moves the intent to `successful` and posts the capture to the ledger, as a real provider confirmation would. Returns 404 for live keys.",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "The successful payment intent",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentIntent"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/test_helpers/balance/release_pending": {
   "post": {
    "tags": [
     "Test helpers"
    ],
    "operationId": "testReleasePending",
    "x-status": "live",
    "summary": "Move all pending money to available now (test keys only)",
    "description": "Skips the settlement delay for this merchant's captured test payments.",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "How many payments were released",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "released"
         ],
         "properties": {
          "object": {
           "const": "test_helper_result"
          },
          "released": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/brands": {
   "get": {
    "tags": [
     "Brands"
    ],
    "operationId": "listBrands",
    "x-status": "live",
    "summary": "List brands",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Brand"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/customers": {
   "get": {
    "tags": [
     "Customers"
    ],
    "operationId": "listCustomers",
    "x-status": "live",
    "summary": "List customers",
    "parameters": [
     {
      "$ref": "#/components/parameters/Limit"
     },
     {
      "$ref": "#/components/parameters/StartingAfter"
     },
     {
      "name": "email",
      "in": "query",
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Customer"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "tags": [
     "Customers"
    ],
    "operationId": "createCustomer",
    "x-status": "live",
    "summary": "Create a customer",
    "description": "Customers are also created automatically from a payment's customer_email.",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
         "email": {
          "type": "string",
          "format": "email"
         },
         "name": {
          "type": "string",
          "maxLength": 200
         },
         "phone": {
          "type": "string",
          "pattern": "^\\+?[0-9]{7,15}$"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Customer"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/customers/{id}": {
   "get": {
    "tags": [
     "Customers"
    ],
    "operationId": "getCustomer",
    "x-status": "live",
    "summary": "A customer with their payment totals",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "allOf": [
          {
           "$ref": "#/components/schemas/Customer"
          },
          {
           "type": "object",
           "required": [
            "payments",
            "total_spent",
            "spent"
           ],
           "properties": {
            "payments": {
             "type": "integer",
             "description": "Succeeded payments in every currency"
            },
            "total_spent": {
             "$ref": "#/components/schemas/Amount",
             "description": "Naira only (kept for older clients). Use `spent` for every currency."
            },
            "spent": {
             "type": "array",
             "description": "Succeeded payments per currency, naira first. Empty if none.",
             "items": {
              "type": "object",
              "required": [
               "currency",
               "payments",
               "amount"
              ],
              "properties": {
               "currency": {
                "$ref": "#/components/schemas/Currency"
               },
               "payments": {
                "type": "integer"
               },
               "amount": {
                "$ref": "#/components/schemas/Amount"
               }
              }
             }
            }
           }
          }
         ]
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payment_links": {
   "get": {
    "tags": [
     "Payment links"
    ],
    "operationId": "listPaymentLinks",
    "x-status": "live",
    "summary": "List payment links",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/PaymentLink"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "tags": [
     "Payment links"
    ],
    "operationId": "createPaymentLink",
    "x-status": "live",
    "summary": "Create a payment link",
    "description": "Set `amount` for a fixed price, or leave it out to let the customer enter any amount (optionally within `min_amount` and `max_amount`; a payment must still cover its processing fee). Customers open the link's `path` on the checkout site (checkout API `/checkout/v1/merchants/{handle}/links/{slug}`). `slug` is optional and only has to be unique within your account.",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "title"
        ],
        "properties": {
         "title": {
          "type": "string",
          "maxLength": 120
         },
         "description": {
          "type": "string",
          "maxLength": 500
         },
         "amount": {
          "type": "integer",
          "minimum": 1
         },
         "min_amount": {
          "type": "integer",
          "minimum": 1
         },
         "max_amount": {
          "type": "integer",
          "minimum": 1
         },
         "currency": {
          "$ref": "#/components/schemas/Currency"
         },
         "brand": {
          "type": "string",
          "format": "uuid"
         },
         "slug": {
          "type": "string",
          "pattern": "^[a-z0-9][a-z0-9-]{2,62}$"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentLink"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payment_links/{id}/activate": {
   "post": {
    "tags": [
     "Payment links"
    ],
    "operationId": "activatePaymentLink",
    "x-status": "live",
    "summary": "Activate a payment link",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentLink"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/payment_links/{id}/deactivate": {
   "post": {
    "tags": [
     "Payment links"
    ],
    "operationId": "deactivatePaymentLink",
    "x-status": "live",
    "summary": "Deactivate a payment link",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentLink"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/disputes": {
   "get": {
    "tags": [
     "Disputes"
    ],
    "operationId": "listDisputes",
    "x-status": "live",
    "summary": "List disputes",
    "parameters": [
     {
      "name": "status",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "needs_response",
        "under_review",
        "won",
        "lost"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Dispute"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/disputes/{id}": {
   "get": {
    "tags": [
     "Disputes"
    ],
    "operationId": "getDispute",
    "x-status": "live",
    "summary": "Retrieve a dispute",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Dispute"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/disputes/{id}/files": {
   "get": {
    "tags": [
     "Disputes"
    ],
    "operationId": "listDisputeFiles",
    "x-status": "live",
    "summary": "The dispute's evidence files",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FileList"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "tags": [
     "Disputes"
    ],
    "operationId": "uploadDisputeFile",
    "x-status": "live",
    "summary": "Attach evidence (receipt, delivery proof, messages) before responding",
    "description": "Up to 10 files, while the dispute needs a response and before the deadline (409 `dispute_not_open`, `response_deadline_passed`).",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/FileUpload"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "The file",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/File"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/disputes/{id}/files/{fileId}": {
   "get": {
    "tags": [
     "Disputes"
    ],
    "operationId": "getDisputeFile",
    "x-status": "live",
    "summary": "One evidence file's content",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "name": "fileId",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The file, base64",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FileContent"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/disputes/{id}/files/{fileId}/remove": {
   "post": {
    "tags": [
     "Disputes"
    ],
    "operationId": "removeDisputeFile",
    "x-status": "live",
    "summary": "Remove an evidence file (before responding)",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "name": "fileId",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "The remaining files",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FileList"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/disputes/{id}/respond": {
   "post": {
    "tags": [
     "Disputes"
    ],
    "operationId": "respondToDispute",
    "x-status": "live",
    "summary": "Submit evidence (once, before respond_by)",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "evidence"
        ],
        "properties": {
         "evidence": {
          "type": "string",
          "minLength": 20,
          "maxLength": 10000
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Dispute"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/test_helpers/settlements/run": {
   "post": {
    "tags": [
     "Test helpers"
    ],
    "operationId": "testSettlementsRun",
    "x-status": "live",
    "summary": "Run automatic settlement for this merchant now (test only)",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "object": {
           "const": "test_helper_result"
          },
          "released": {
           "type": "integer"
          },
          "payouts": {
           "type": "array",
           "items": {
            "type": "string",
            "format": "uuid"
           }
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/virtual_accounts": {
   "get": {
    "tags": [
     "Virtual accounts"
    ],
    "operationId": "listVirtualAccounts",
    "x-status": "live",
    "summary": "List dedicated virtual accounts",
    "parameters": [
     {
      "name": "customer",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      },
      "description": "Only this customer's"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/VirtualAccount"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "tags": [
     "Virtual accounts"
    ],
    "operationId": "createVirtualAccount",
    "x-status": "live",
    "summary": "Give a customer a permanent account number",
    "description": "Returns the customer's existing active account if there is one. Every transfer into it becomes a successful payment.",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
         "customer": {
          "type": "string",
          "format": "uuid"
         },
         "customer_email": {
          "type": "string",
          "format": "email"
         },
         "customer_name": {
          "type": "string"
         },
         "brand": {
          "type": "string",
          "format": "uuid"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/VirtualAccount"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/virtual_accounts/{id}/close": {
   "post": {
    "tags": [
     "Virtual accounts"
    ],
    "operationId": "closeVirtualAccount",
    "x-status": "live",
    "summary": "Close a virtual account",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/VirtualAccount"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/test_helpers/virtual_accounts/{id}/simulate_transfer": {
   "post": {
    "tags": [
     "Test helpers"
    ],
    "operationId": "testSimulateVirtualAccountTransfer",
    "x-status": "live",
    "summary": "Pretend money arrived in a virtual account (test only)",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "amount"
        ],
        "properties": {
         "amount": {
          "type": "integer",
          "minimum": 1
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "object": {
           "const": "test_helper_result"
          },
          "webhook": {
           "type": "string"
          },
          "provider_reference": {
           "type": "string"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/customers/{id}/payment_methods": {
   "get": {
    "tags": [
     "Subscriptions"
    ],
    "operationId": "listPaymentMethods",
    "x-status": "live",
    "summary": "A customer's saved cards",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/PaymentMethod"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/subscriptions": {
   "get": {
    "tags": [
     "Subscriptions"
    ],
    "operationId": "listSubscriptions",
    "x-status": "live",
    "summary": "List subscriptions",
    "parameters": [
     {
      "name": "customer",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      },
      "description": "Only this customer's"
     },
     {
      "name": "status",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "active",
        "past_due",
        "canceled"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Subscription"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "tags": [
     "Subscriptions"
    ],
    "operationId": "createSubscription",
    "x-status": "live",
    "summary": "Charge a saved card every week, month or year",
    "description": "Save the card first: create a payment with save_payment_method true and a customer, and pay it at checkout. The first charge happens at start_at (default now).",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "payment_method",
         "amount",
         "interval",
         "description"
        ],
        "properties": {
         "payment_method": {
          "type": "string",
          "format": "uuid"
         },
         "amount": {
          "type": "integer",
          "minimum": 1
         },
         "currency": {
          "$ref": "#/components/schemas/Currency"
         },
         "interval": {
          "type": "string",
          "enum": [
           "weekly",
           "monthly",
           "yearly"
          ]
         },
         "description": {
          "type": "string",
          "maxLength": 200
         },
         "brand": {
          "type": "string",
          "format": "uuid"
         },
         "start_at": {
          "type": "string",
          "format": "date-time"
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Subscription"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/subscriptions/{id}/cancel": {
   "post": {
    "tags": [
     "Subscriptions"
    ],
    "operationId": "cancelSubscription",
    "x-status": "live",
    "summary": "Cancel a subscription",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Subscription"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/invoices": {
   "get": {
    "tags": [
     "Invoices"
    ],
    "operationId": "listInvoices",
    "x-status": "live",
    "summary": "List invoices",
    "parameters": [
     {
      "name": "status",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "draft",
        "open",
        "paid",
        "void"
       ]
      }
     },
     {
      "name": "customer",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      },
      "description": "Only this customer's"
     }
    ],
    "responses": {
     "200": {
      "description": "Invoices",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "required": [
          "object",
          "data"
         ],
         "properties": {
          "object": {
           "const": "list"
          },
          "data": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Invoice"
           }
          },
          "has_more": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "post": {
    "tags": [
     "Invoices"
    ],
    "operationId": "createInvoice",
    "x-status": "live",
    "summary": "Create a draft invoice",
    "parameters": [
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "customer",
         "items"
        ],
        "properties": {
         "customer": {
          "type": "string",
          "format": "uuid"
         },
         "currency": {
          "$ref": "#/components/schemas/Currency"
         },
         "brand": {
          "type": "string",
          "format": "uuid"
         },
         "items": {
          "type": "array",
          "minItems": 1,
          "items": {
           "type": "object",
           "required": [
            "description",
            "quantity",
            "unit_amount"
           ],
           "properties": {
            "description": {
             "type": "string",
             "maxLength": 200
            },
            "quantity": {
             "type": "integer",
             "minimum": 1
            },
            "unit_amount": {
             "type": "integer",
             "minimum": 1
            }
           }
          }
         },
         "due_date": {
          "type": "string",
          "format": "date"
         },
         "memo": {
          "type": "string",
          "maxLength": 1000
         }
        }
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Invoice"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/invoices/{id}": {
   "get": {
    "tags": [
     "Invoices"
    ],
    "operationId": "getInvoice",
    "x-status": "live",
    "summary": "Retrieve an invoice",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     }
    ],
    "responses": {
     "200": {
      "description": "The invoice",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Invoice"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/invoices/{id}/finalize": {
   "post": {
    "tags": [
     "Invoices"
    ],
    "operationId": "finalizeInvoice",
    "x-status": "live",
    "summary": "Finalize, create its payment and email the customer the checkout link",
    "description": "Returns hosted_invoice_url. The invoice becomes paid when that payment succeeds (invoice.paid event).",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "The open invoice",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Invoice"
        }
       }
      }
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/invoices/{id}/void": {
   "post": {
    "tags": [
     "Invoices"
    ],
    "operationId": "voidInvoice",
    "x-status": "live",
    "summary": "Void an unpaid invoice",
    "parameters": [
     {
      "$ref": "#/components/parameters/Id"
     },
     {
      "$ref": "#/components/parameters/IdempotencyKey"
     }
    ],
    "responses": {
     "200": {
      "description": "The void invoice",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Invoice"
        }
       }
      }
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  }
 },
 "components": {
  "parameters": {
   "IdempotencyKey": {
    "name": "Idempotency-Key",
    "in": "header",
    "required": true,
    "description": "A unique key per logical request, for example a UUID. Up to 255 characters.",
    "schema": {
     "type": "string",
     "minLength": 1,
     "maxLength": 255
    },
    "example": "6f1c2a3e-9b8d-4e7f-a0c1-2d3e4f5a6b7c"
   },
   "Limit": {
    "name": "limit",
    "in": "query",
    "schema": {
     "type": "integer",
     "minimum": 1,
     "maximum": 100,
     "default": 20
    }
   },
   "StartingAfter": {
    "name": "starting_after",
    "in": "query",
    "description": "The id of the last item on the previous page.",
    "schema": {
     "type": "string",
     "format": "uuid"
    }
   },
   "Id": {
    "name": "id",
    "in": "path",
    "required": true,
    "schema": {
     "type": "string",
     "format": "uuid"
    }
   }
  },
  "schemas": {
   "CreatePaymentIntent": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "amount",
     "currency"
    ],
    "properties": {
     "amount": {
      "type": "integer",
      "minimum": 1,
      "example": 1000000
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "reference": {
      "type": "string",
      "maxLength": 100,
      "description": "Your own reference; unique per merchant and mode."
     },
     "description": {
      "type": "string",
      "maxLength": 500
     },
     "customer_email": {
      "type": "string",
      "format": "email"
     },
     "customer_name": {
      "type": "string",
      "maxLength": 200
     },
     "brand": {
      "type": "string",
      "format": "uuid",
      "description": "Attribute the payment to one of your brands."
     },
     "save_payment_method": {
      "type": "boolean",
      "description": "Save the card used at checkout for subscriptions. Needs customer_email."
     },
     "metadata": {
      "$ref": "#/components/schemas/Metadata"
     },
     "return_url": {
      "type": "string",
      "maxLength": 2000,
      "example": "https://example.com/orders/1042/complete",
      "description": "Where checkout sends the customer after a successful payment, with `payment_intent` and\n`status` added to the query. https only (http is accepted in test mode). Don't treat the\nredirect as proof of payment: confirm with the webhook or GET /v1/payment_intents/{id}.\n"
     }
    }
   },
   "Currency": {
    "type": "string",
    "enum": [
     "NGN",
     "USD"
    ]
   },
   "Metadata": {
    "type": "object",
    "maxProperties": 20,
    "additionalProperties": {
     "type": "string",
     "maxLength": 500
    },
    "example": {
     "order_id": "10293"
    }
   },
   "PaymentIntent": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "amount",
     "currency",
     "status",
     "fees",
     "metadata",
     "created_at",
     "updated_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid",
      "example": "0b6f3f0e-6c1a-4d8e-9b0a-5f1e2d3c4b5a"
     },
     "object": {
      "const": "payment_intent"
     },
     "livemode": {
      "type": "boolean",
      "example": false
     },
     "amount": {
      "$ref": "#/components/schemas/Amount",
      "example": 1000000
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "status": {
      "$ref": "#/components/schemas/PaymentIntentStatus"
     },
     "reference": {
      "type": [
       "string",
       "null"
      ],
      "example": "order-10293"
     },
     "description": {
      "type": [
       "string",
       "null"
      ]
     },
     "customer_email": {
      "type": [
       "string",
       "null"
      ],
      "example": "ada@example.com"
     },
     "brand": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "customer": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "payment_link": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "metadata": {
      "$ref": "#/components/schemas/Metadata"
     },
     "fees": {
      "type": "object",
      "required": [
       "fee",
       "vat",
       "net"
      ],
      "description": "An estimate (at the card price) until the payment succeeds; then final, at the price for the channel and provider that took it. fee + vat + net = amount.",
      "properties": {
       "fee": {
        "$ref": "#/components/schemas/Amount",
        "example": 15000
       },
       "vat": {
        "$ref": "#/components/schemas/Amount",
        "example": 1125
       },
       "net": {
        "$ref": "#/components/schemas/Amount",
        "example": 983875
       }
      }
     },
     "failure_code": {
      "type": [
       "string",
       "null"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time"
     },
     "paid_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time",
      "description": "When the payment became successful."
     },
     "canceled_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "return_url": {
      "type": [
       "string",
       "null"
      ],
      "description": "Where checkout sends the customer after paying."
     },
     "client_secret": {
      "type": "string",
      "description": "Only in the response that creates the payment. Give it to the customer's checkout page; it can act on this one payment only."
     }
    }
   },
   "Amount": {
    "type": "integer",
    "minimum": 0,
    "description": "Minor units (kobo, cents)."
   },
   "PaymentIntentStatus": {
    "type": "string",
    "description": "`created` not paid yet; `processing` the customer started paying (entered a card, or was given\nan account to transfer into); `successful` the money arrived; `failed` the last try failed and\nthe customer may try again; `abandoned` processing for 30 minutes with no money (the customer may\nstill pay); `canceled` canceled by the business. Money that arrives late always makes a payment\n`successful`.\n",
    "enum": [
     "created",
     "processing",
     "successful",
     "failed",
     "abandoned",
     "canceled"
    ]
   },
   "Error": {
    "type": "object",
    "required": [
     "error"
    ],
    "properties": {
     "error": {
      "type": "object",
      "required": [
       "type",
       "code",
       "message"
      ],
      "properties": {
       "type": {
        "type": "string",
        "enum": [
         "invalid_request_error",
         "authentication_error",
         "idempotency_error",
         "state_error",
         "api_error"
        ]
       },
       "code": {
        "type": "string"
       },
       "message": {
        "type": "string"
       },
       "param": {
        "type": "string"
       }
      }
     }
    }
   },
   "PaymentIntentList": {
    "type": "object",
    "required": [
     "object",
     "data",
     "has_more"
    ],
    "properties": {
     "object": {
      "const": "list"
     },
     "data": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/PaymentIntent"
      }
     },
     "has_more": {
      "type": "boolean"
     }
    }
   },
   "ChargeAttempt": {
    "type": "object",
    "description": "One try at taking the payment. Which provider handled it isn't shown to merchants.",
    "required": [
     "id",
     "object",
     "channel",
     "status"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "charge_attempt"
     },
     "channel": {
      "type": "string",
      "enum": [
       "card",
       "bank_transfer",
       "virtual_account"
      ]
     },
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "succeeded",
       "failed",
       "unknown",
       "canceled"
      ]
     },
     "failure_code": {
      "type": [
       "string",
       "null"
      ]
     }
    }
   },
   "Balance": {
    "type": "object",
    "required": [
     "object",
     "livemode",
     "pending",
     "available",
     "reserve",
     "payout_in_flight"
    ],
    "properties": {
     "object": {
      "const": "balance"
     },
     "livemode": {
      "type": "boolean"
     },
     "brand": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid",
      "description": "The brand asked for; null for the whole business"
     },
     "pending": {
      "description": "Captured, not yet settleable.",
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BalanceAmount"
      },
      "example": [
       {
        "currency": "NGN",
        "amount": 983875
       }
      ]
     },
     "available": {
      "description": "Can be paid out.",
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BalanceAmount"
      },
      "example": [
       {
        "currency": "NGN",
        "amount": 4520000
       }
      ]
     },
     "reserve": {
      "description": "Rolling reserve held against chargebacks.",
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BalanceAmount"
      },
      "example": [
       {
        "currency": "NGN",
        "amount": 120000
       }
      ]
     },
     "payout_in_flight": {
      "description": "Sent to a bank, not yet confirmed.",
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BalanceAmount"
      },
      "example": [
       {
        "currency": "NGN",
        "amount": 0
       }
      ]
     },
     "refund_in_flight": {
      "description": "Being refunded to customers, not yet confirmed by the provider.",
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BalanceAmount"
      },
      "example": [
       {
        "currency": "NGN",
        "amount": 0
       }
      ]
     },
     "dispute_hold": {
      "description": "Held while a dispute is decided.",
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BalanceAmount"
      },
      "example": [
       {
        "currency": "NGN",
        "amount": 0
       }
      ]
     }
    }
   },
   "BalanceAmount": {
    "type": "object",
    "required": [
     "currency",
     "amount"
    ],
    "properties": {
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "amount": {
      "$ref": "#/components/schemas/Amount"
     }
    }
   },
   "BalanceTransactionList": {
    "type": "object",
    "required": [
     "object",
     "data",
     "has_more"
    ],
    "properties": {
     "object": {
      "const": "list"
     },
     "data": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/BalanceTransaction"
      }
     },
     "has_more": {
      "type": "boolean"
     }
    }
   },
   "BalanceTransaction": {
    "type": "object",
    "required": [
     "id",
     "object",
     "type",
     "description",
     "amount",
     "balance_after",
     "currency",
     "bucket",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "example": "10234"
     },
     "object": {
      "const": "balance_transaction"
     },
     "type": {
      "type": "string",
      "example": "charge.capture",
      "description": "e.g. charge.capture, charge.release, payout.hold, payout.settle, refund.hold"
     },
     "description": {
      "type": "string",
      "example": "Payment received"
     },
     "bucket": {
      "type": "string",
      "enum": [
       "pending",
       "available",
       "reserve",
       "payout_in_flight",
       "refund_in_flight",
       "dispute_hold"
      ]
     },
     "amount": {
      "type": "integer",
      "description": "Signed; positive adds to the bucket."
     },
     "balance_after": {
      "type": "integer",
      "description": "The bucket's balance after this line."
     },
     "gross": {
      "type": "integer",
      "description": "Payments only: what the customer paid."
     },
     "fee": {
      "type": "integer",
      "description": "Payments only: Biftpay's fee plus VAT, taken from gross."
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "source_id": {
      "type": [
       "string",
       "null"
      ],
      "description": "The payment, payout or refund that caused it."
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "FxPreview": {
    "type": "object",
    "required": [
     "object",
     "rate",
     "usd_available",
     "min_usd",
     "max_usd",
     "daily_cap_usd",
     "converted_today_usd",
     "blocked"
    ],
    "properties": {
     "object": {
      "const": "fx_preview"
     },
     "rate": {
      "oneOf": [
       {
        "$ref": "#/components/schemas/FxRate"
       },
       {
        "type": "null"
       }
      ]
     },
     "usd_available": {
      "type": "integer"
     },
     "min_usd": {
      "type": "integer"
     },
     "max_usd": {
      "type": "integer",
      "description": "The most that can convert now (balance, maximum and today's cap)."
     },
     "daily_cap_usd": {
      "type": [
       "integer",
       "null"
      ]
     },
     "converted_today_usd": {
      "type": "integer"
     },
     "blocked": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "conversions_paused",
       "no_rate",
       "rate_stale",
       "balance_below_minimum",
       "daily_cap_reached",
       null
      ]
     },
     "usd_amount": {
      "type": "integer"
     },
     "ngn_amount": {
      "type": "integer",
      "description": "The naira usd_amount gives at this rate (rounded down)."
     }
    }
   },
   "FxRate": {
    "type": "object",
    "required": [
     "id",
     "rate",
     "note",
     "set_by",
     "created_at",
     "stale"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "rate": {
      "type": "string",
      "description": "Naira per dollar."
     },
     "note": {
      "type": [
       "string",
       "null"
      ]
     },
     "set_by": {
      "type": "string"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "stale": {
      "type": "boolean",
      "description": "Older than the allowed age: conversions wait for a new rate."
     }
    }
   },
   "FxConversion": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "usd_amount",
     "rate",
     "ngn_amount",
     "brand",
     "source",
     "payout",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "fx_conversion"
     },
     "livemode": {
      "type": "boolean"
     },
     "usd_amount": {
      "type": "integer"
     },
     "rate": {
      "type": "string"
     },
     "ngn_amount": {
      "type": "integer"
     },
     "brand": {
      "type": [
       "string",
       "null"
      ]
     },
     "source": {
      "type": "string",
      "enum": [
       "merchant",
       "auto",
       "staff"
      ]
     },
     "payout": {
      "type": [
       "string",
       "null"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "CreateBankAccount": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "bank_code",
     "account_number"
    ],
    "properties": {
     "bank_code": {
      "type": "string",
      "pattern": "^[0-9]{3,6}$",
      "example": "999"
     },
     "account_number": {
      "type": "string",
      "pattern": "^[0-9]{10}$",
      "description": "10-digit NUBAN",
      "example": "0123456789"
     }
    }
   },
   "BankAccount": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "bank_code",
     "bank_name",
     "account_number_last4",
     "account_name",
     "verified_at",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "bank_account"
     },
     "livemode": {
      "type": "boolean"
     },
     "bank_code": {
      "type": "string",
      "example": "999"
     },
     "bank_name": {
      "type": "string",
      "example": "Sandbox Bank"
     },
     "account_number_last4": {
      "type": "string",
      "example": "6789"
     },
     "account_name": {
      "type": "string",
      "description": "As returned by the bank's name enquiry.",
      "example": "SANDBOX ACCOUNT 6789"
     },
     "verified_at": {
      "type": "string",
      "format": "date-time"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "CreatePayout": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "amount",
     "currency",
     "bank_account_id"
    ],
    "properties": {
     "amount": {
      "type": "integer",
      "minimum": 1,
      "example": 500000
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "bank_account_id": {
      "type": "string",
      "format": "uuid",
      "description": "A registered, name-checked destination account."
     },
     "narration": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
     },
     "brand": {
      "type": "string",
      "format": "uuid",
      "description": "Pay out of this brand's balance. Defaults to the business's own brand."
     },
     "otp": {
      "description": "Required when a signed-in user (not an API key) requests the payout. From `POST /v1/payouts/otp`.",
      "oneOf": [
       {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "challenge_id",
         "code"
        ],
        "properties": {
         "challenge_id": {
          "type": "string",
          "format": "uuid"
         },
         "code": {
          "type": "string",
          "pattern": "^[0-9]{6}$"
         }
        }
       },
       {
        "type": "object",
        "additionalProperties": false,
        "required": [
         "totp_code"
        ],
        "properties": {
         "totp_code": {
          "type": "string",
          "pattern": "^[0-9]{6}$"
         }
        }
       }
      ]
     }
    }
   },
   "Payout": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "amount",
     "fee",
     "vat",
     "total_debited",
     "currency",
     "status",
     "bank_account",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid",
      "description": "Also the reference sent to the bank."
     },
     "object": {
      "const": "payout"
     },
     "livemode": {
      "type": "boolean"
     },
     "amount": {
      "$ref": "#/components/schemas/Amount",
      "example": 500000
     },
     "fee": {
      "$ref": "#/components/schemas/Amount",
      "example": 5000
     },
     "vat": {
      "$ref": "#/components/schemas/Amount",
      "example": 375
     },
     "total_debited": {
      "$ref": "#/components/schemas/Amount",
      "example": 505375,
      "description": "amount + fee + vat"
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "status": {
      "$ref": "#/components/schemas/PayoutStatus"
     },
     "narration": {
      "type": [
       "string",
       "null"
      ]
     },
     "brand": {
      "type": "string",
      "format": "uuid",
      "description": "The brand whose balance pays it."
     },
     "review_reasons": {
      "type": "array",
      "description": "Why Biftpay is checking it before it's sent (status awaiting_approval); empty otherwise.\nnew_bank_account - the first payout to an account added in the last 24 hours;\naccount_review - the business or brand is under review, or several disputes arrived this week;\nsecurity_change - a password or authenticator change by the requester, or a settlement account change, in the last 24 hours;\nunusual - far larger than this merchant has paid out before, or most of the balance after 30 quiet days;\namount - over an approval threshold Biftpay set for this merchant.\n",
      "items": {
       "type": "string",
       "enum": [
        "amount",
        "new_bank_account",
        "account_review",
        "security_change",
        "unusual"
       ]
      }
     },
     "bank_account": {
      "type": "object",
      "required": [
       "id",
       "bank_name",
       "account_number_last4",
       "account_name"
      ],
      "properties": {
       "id": {
        "type": "string",
        "format": "uuid"
       },
       "bank_name": {
        "type": "string",
        "example": "Sandbox Bank"
       },
       "account_number_last4": {
        "type": "string",
        "example": "6789"
       },
       "account_name": {
        "type": "string",
        "example": "SANDBOX ACCOUNT 6789"
       }
      }
     },
     "approved_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "failure_code": {
      "type": [
       "string",
       "null"
      ],
      "example": null
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "paid_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "failed_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "canceled_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     }
    }
   },
   "PayoutStatus": {
    "type": "string",
    "enum": [
     "awaiting_approval",
     "queued",
     "processing",
     "paid",
     "failed",
     "canceled"
    ],
    "description": "`awaiting_approval` (Biftpay is reviewing it first, e.g. a large amount) -> `queued` -> `processing`\n(sent, waiting for the bank's confirmation) -> `paid` or `failed`. `canceled` is only\npossible before sending.\n"
   },
   "PayoutList": {
    "type": "object",
    "required": [
     "object",
     "data",
     "has_more"
    ],
    "properties": {
     "object": {
      "const": "list"
     },
     "data": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Payout"
      }
     },
     "has_more": {
      "type": "boolean"
     }
    }
   },
   "UsdtSettings": {
    "type": "object",
    "required": [
     "enabled",
     "cooling_hours",
     "min_usd",
     "max_usd",
     "updated_by",
     "updated_at"
    ],
    "properties": {
     "enabled": {
      "type": "boolean"
     },
     "cooling_hours": {
      "type": "integer"
     },
     "min_usd": {
      "type": "integer"
     },
     "max_usd": {
      "type": [
       "integer",
       "null"
      ]
     },
     "updated_by": {
      "type": "string"
     },
     "updated_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "CryptoWallet": {
    "type": "object",
    "required": [
     "id",
     "object",
     "asset",
     "network",
     "network_label",
     "address",
     "label",
     "usable",
     "usable_from",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "crypto_wallet"
     },
     "asset": {
      "const": "USDT"
     },
     "network": {
      "type": "string",
      "enum": [
       "tron",
       "ethereum",
       "polygon",
       "bsc"
      ]
     },
     "network_label": {
      "type": "string"
     },
     "address": {
      "type": "string"
     },
     "label": {
      "type": [
       "string",
       "null"
      ]
     },
     "usable": {
      "type": "boolean",
      "description": "Past the cooling-off period: can receive payouts."
     },
     "usable_from": {
      "type": "string",
      "format": "date-time"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "UsdtPreview": {
    "type": "object",
    "required": [
     "object",
     "usd_available",
     "min_usd",
     "max_usd",
     "available_now"
    ],
    "properties": {
     "object": {
      "const": "usdt_preview"
     },
     "usd_available": {
      "type": "integer"
     },
     "min_usd": {
      "type": "integer"
     },
     "max_usd": {
      "type": [
       "integer",
       "null"
      ]
     },
     "available_now": {
      "type": "boolean",
      "description": "USDT payouts are on and a partner is connected."
     },
     "usd_amount": {
      "type": "integer"
     },
     "fee": {
      "type": "integer"
     },
     "vat": {
      "type": "integer"
     },
     "net_usd": {
      "type": "integer"
     },
     "usdt_estimate": {
      "type": "string",
      "description": "USDT the wallet should receive."
     }
    }
   },
   "CryptoPayout": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "wallet",
     "usd_amount",
     "fee",
     "vat",
     "net_usd",
     "usdt_amount",
     "status",
     "tx_hash",
     "failure_code",
     "created_at",
     "paid_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "crypto_payout"
     },
     "livemode": {
      "type": "boolean"
     },
     "wallet": {
      "type": "string",
      "format": "uuid"
     },
     "network": {
      "type": "string"
     },
     "address": {
      "type": "string"
     },
     "usd_amount": {
      "type": "integer"
     },
     "fee": {
      "type": "integer"
     },
     "vat": {
      "type": "integer"
     },
     "net_usd": {
      "type": "integer"
     },
     "usdt_amount": {
      "type": [
       "string",
       "null"
      ],
      "description": "USDT the wallet received, as the partner reports it."
     },
     "status": {
      "type": "string",
      "enum": [
       "queued",
       "processing",
       "paid",
       "failed"
      ]
     },
     "tx_hash": {
      "type": [
       "string",
       "null"
      ],
      "description": "The on-chain transaction."
     },
     "failure_code": {
      "type": [
       "string",
       "null"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "paid_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     }
    }
   },
   "OtpProof": {
    "oneOf": [
     {
      "type": "object",
      "additionalProperties": false,
      "required": [
       "challenge_id",
       "code"
      ],
      "properties": {
       "challenge_id": {
        "type": "string",
        "format": "uuid"
       },
       "code": {
        "type": "string",
        "pattern": "^[0-9]{6}$"
       }
      }
     },
     {
      "type": "object",
      "additionalProperties": false,
      "required": [
       "totp_code"
      ],
      "properties": {
       "totp_code": {
        "type": "string",
        "pattern": "^[0-9]{6}$"
       }
      }
     }
    ]
   },
   "CreateRefund": {
    "type": "object",
    "additionalProperties": false,
    "required": [
     "payment_intent"
    ],
    "properties": {
     "payment_intent": {
      "type": "string",
      "format": "uuid"
     },
     "amount": {
      "type": "integer",
      "minimum": 1,
      "description": "Defaults to the full remaining amount."
     },
     "reason": {
      "type": "string",
      "enum": [
       "requested_by_customer",
       "duplicate",
       "fraudulent"
      ]
     }
    }
   },
   "Refund": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "payment_intent",
     "amount",
     "currency",
     "status",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "refund"
     },
     "livemode": {
      "type": "boolean"
     },
     "payment_intent": {
      "type": "string",
      "format": "uuid"
     },
     "amount": {
      "$ref": "#/components/schemas/Amount"
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "reason": {
      "type": [
       "string",
       "null"
      ]
     },
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "succeeded",
       "failed"
      ]
     },
     "failure_code": {
      "type": [
       "string",
       "null"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "succeeded_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "failed_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     }
    }
   },
   "EventType": {
    "type": "string",
    "enum": [
     "payment_intent.successful",
     "payment_intent.failed",
     "payment_intent.abandoned",
     "payment_intent.canceled",
     "refund.succeeded",
     "refund.failed",
     "payout.paid",
     "payout.failed",
     "payout.canceled",
     "dispute.created",
     "dispute.won",
     "dispute.lost",
     "invoice.paid",
     "crypto_payout.paid",
     "crypto_payout.failed"
    ]
   },
   "WebhookEndpoint": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "url",
     "events",
     "status",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "webhook_endpoint"
     },
     "livemode": {
      "type": "boolean"
     },
     "url": {
      "type": "string",
      "format": "uri"
     },
     "events": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/EventType"
      }
     },
     "status": {
      "type": "string",
      "enum": [
       "enabled",
       "disabled"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "EventList": {
    "type": "object",
    "required": [
     "object",
     "data",
     "has_more"
    ],
    "properties": {
     "object": {
      "const": "list"
     },
     "data": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Event"
      }
     },
     "has_more": {
      "type": "boolean"
     }
    }
   },
   "Event": {
    "type": "object",
    "required": [
     "id",
     "object",
     "type",
     "livemode",
     "created_at",
     "data"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "event"
     },
     "type": {
      "$ref": "#/components/schemas/EventType"
     },
     "livemode": {
      "type": "boolean"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "data": {
      "type": "object",
      "required": [
       "object"
      ],
      "properties": {
       "object": {
        "type": "object",
        "description": "The payment, payout or refund as it was at that moment."
       }
      }
     },
     "deliveries": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "endpoint_id": {
         "type": "string",
         "format": "uuid"
        },
        "status": {
         "type": "string",
         "enum": [
          "pending",
          "delivered",
          "retrying",
          "failed"
         ]
        },
        "attempts": {
         "type": "integer"
        },
        "last_response_status": {
         "type": [
          "integer",
          "null"
         ]
        }
       }
      }
     }
    }
   },
   "Brand": {
    "type": "object",
    "required": [
     "id",
     "object",
     "name",
     "status",
     "is_default",
     "settlement_bank_account",
     "review",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "brand"
     },
     "name": {
      "type": "string"
     },
     "display_name": {
      "type": [
       "string",
       "null"
      ]
     },
     "support_email": {
      "type": [
       "string",
       "null"
      ]
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "archived"
      ]
     },
     "is_default": {
      "type": "boolean",
      "description": "The business itself, created at signup with the business name. Can't be archived; anything without a brand belongs to it."
     },
     "settlement_bank_account": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid",
      "description": "Where this brand's naira settles; null uses the business's settlement account."
     },
     "category": {
      "oneOf": [
       {
        "$ref": "#/components/schemas/BrandCategory"
       },
       {
        "type": "null"
       }
      ]
     },
     "description": {
      "type": [
       "string",
       "null"
      ]
     },
     "website": {
      "type": [
       "string",
       "null"
      ]
     },
     "support_phone": {
      "type": [
       "string",
       "null"
      ]
     },
     "business_name_number": {
      "type": [
       "string",
       "null"
      ]
     },
     "review": {
      "$ref": "#/components/schemas/BrandReview"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "BrandCategory": {
    "type": "string",
    "enum": [
     "retail_ecommerce",
     "fashion_beauty",
     "food_restaurants",
     "supermarkets",
     "education",
     "healthcare_pharmacy",
     "travel_transport",
     "hotels_hospitality",
     "logistics",
     "software_saas",
     "digital_services",
     "media_entertainment",
     "events_tickets",
     "real_estate",
     "construction",
     "agriculture",
     "manufacturing",
     "professional_services",
     "legal",
     "accounting_audit_tax",
     "jewellery_precious_metals",
     "car_dealers",
     "religious_organisation",
     "ngo_charity",
     "other",
     "betting_gaming",
     "crypto_digital_assets",
     "forex_investment",
     "lending_credit",
     "money_transfer"
    ],
    "description": "The last five are restricted and need a licence."
   },
   "BrandReview": {
    "type": "object",
    "required": [
     "status",
     "reason",
     "risk",
     "licence_needed",
     "requirements",
     "submitted_at",
     "reviewed_at"
    ],
    "properties": {
     "status": {
      "type": "string",
      "enum": [
       "pending",
       "approved",
       "rejected",
       "suspended"
      ],
      "description": "Only `approved` brands take live payments. A suspended brand's live balance isn't paid out or settled."
     },
     "reason": {
      "type": [
       "string",
       "null"
      ],
      "description": "Compliance's reason for a rejection or suspension."
     },
     "risk": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "low",
       "review",
       "restricted",
       null
      ],
      "description": "null for the business's own brand."
     },
     "licence_needed": {
      "type": [
       "string",
       "null"
      ],
      "description": "The licence a restricted category needs."
     },
     "requirements": {
      "type": "array",
      "items": {
       "type": "string",
       "enum": [
        "licence"
       ]
      },
      "description": "Still needed before compliance can approve."
     },
     "submitted_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "reviewed_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     }
    }
   },
   "Customer": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "customer"
     },
     "livemode": {
      "type": "boolean"
     },
     "email": {
      "type": [
       "string",
       "null"
      ]
     },
     "name": {
      "type": [
       "string",
       "null"
      ]
     },
     "phone": {
      "type": [
       "string",
       "null"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "PaymentLink": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "slug",
     "path",
     "title",
     "currency",
     "status",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "payment_link"
     },
     "livemode": {
      "type": "boolean"
     },
     "brand": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "slug": {
      "type": "string",
      "description": "Unique within the merchant and mode."
     },
     "path": {
      "type": "string",
      "description": "Where customers pay, on the checkout site: `/pay/<handle>/<slug>` (live) or\n`/pay/test/<handle>/<slug>` (test). Links made before merchant handles keep `/pay/<slug>`.\n",
      "example": "/pay/kitty-inc/black-friday"
     },
     "title": {
      "type": "string"
     },
     "description": {
      "type": [
       "string",
       "null"
      ]
     },
     "amount": {
      "type": [
       "integer",
       "null"
      ]
     },
     "min_amount": {
      "type": [
       "integer",
       "null"
      ]
     },
     "max_amount": {
      "type": [
       "integer",
       "null"
      ]
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "inactive"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "Dispute": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "merchant_id",
     "payment_intent",
     "amount",
     "held_amount",
     "currency",
     "reason",
     "status",
     "respond_by",
     "created_at",
     "fee",
     "fee_vat"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "dispute"
     },
     "livemode": {
      "type": "boolean"
     },
     "merchant_id": {
      "type": "string",
      "format": "uuid"
     },
     "payment_intent": {
      "type": "string",
      "format": "uuid"
     },
     "amount": {
      "$ref": "#/components/schemas/Amount"
     },
     "held_amount": {
      "$ref": "#/components/schemas/Amount"
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "reason": {
      "type": "string",
      "enum": [
       "fraudulent",
       "product_not_received",
       "duplicate",
       "credit_not_processed",
       "general"
      ]
     },
     "status": {
      "type": "string",
      "enum": [
       "needs_response",
       "under_review",
       "won",
       "lost"
      ]
     },
     "respond_by": {
      "type": "string",
      "format": "date-time"
     },
     "evidence": {
      "type": [
       "string",
       "null"
      ]
     },
     "evidence_submitted_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "resolved_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "fee": {
      "$ref": "#/components/schemas/Amount",
      "description": "Chargeback fee, charged when the dispute is lost (0 otherwise)."
     },
     "fee_vat": {
      "$ref": "#/components/schemas/Amount",
      "description": "VAT on the chargeback fee."
     }
    }
   },
   "FileList": {
    "type": "object",
    "required": [
     "object",
     "data",
     "has_more"
    ],
    "properties": {
     "object": {
      "const": "list"
     },
     "data": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/File"
      }
     },
     "has_more": {
      "type": "boolean"
     }
    }
   },
   "File": {
    "type": "object",
    "required": [
     "id",
     "object",
     "file_name",
     "content_type",
     "size",
     "uploaded_by",
     "message",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "file"
     },
     "file_name": {
      "type": "string"
     },
     "content_type": {
      "type": "string"
     },
     "size": {
      "type": "integer"
     },
     "uploaded_by": {
      "type": "string",
      "enum": [
       "merchant",
       "biftpay"
      ]
     },
     "message": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid",
      "description": "The case message it's attached to."
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "FileUpload": {
    "type": "object",
    "required": [
     "file_name",
     "content_type",
     "data"
    ],
    "properties": {
     "file_name": {
      "type": "string",
      "maxLength": 200
     },
     "content_type": {
      "type": "string",
      "enum": [
       "application/pdf",
       "image/jpeg",
       "image/png"
      ]
     },
     "data": {
      "type": "string",
      "description": "Base64; up to 5 MB decoded"
     }
    }
   },
   "FileContent": {
    "type": "object",
    "required": [
     "object",
     "file_name",
     "content_type",
     "data"
    ],
    "properties": {
     "object": {
      "const": "file_content"
     },
     "file_name": {
      "type": "string"
     },
     "content_type": {
      "type": "string"
     },
     "data": {
      "type": "string",
      "description": "Base64"
     }
    }
   },
   "VirtualAccount": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "customer",
     "account_number",
     "bank_name",
     "account_name",
     "currency",
     "status",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "virtual_account"
     },
     "livemode": {
      "type": "boolean"
     },
     "customer": {
      "type": "string",
      "format": "uuid"
     },
     "brand": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "account_number": {
      "type": "string"
     },
     "bank_name": {
      "type": "string"
     },
     "account_name": {
      "type": "string"
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "closed"
      ]
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "PaymentMethod": {
    "type": "object",
    "required": [
     "id",
     "object",
     "last4",
     "exp_month",
     "exp_year",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "payment_method"
     },
     "brand": {
      "type": [
       "string",
       "null"
      ]
     },
     "last4": {
      "type": "string"
     },
     "exp_month": {
      "type": "integer"
     },
     "exp_year": {
      "type": "integer"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "Subscription": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "customer",
     "payment_method",
     "description",
     "amount",
     "currency",
     "interval",
     "status",
     "next_charge_at",
     "failed_attempts",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "subscription"
     },
     "livemode": {
      "type": "boolean"
     },
     "customer": {
      "type": "string",
      "format": "uuid"
     },
     "payment_method": {
      "type": "string",
      "format": "uuid"
     },
     "brand": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "description": {
      "type": "string"
     },
     "amount": {
      "$ref": "#/components/schemas/Amount"
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "interval": {
      "type": "string",
      "enum": [
       "weekly",
       "monthly",
       "yearly"
      ]
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "past_due",
       "canceled"
      ]
     },
     "next_charge_at": {
      "type": "string",
      "format": "date-time"
     },
     "failed_attempts": {
      "type": "integer"
     },
     "latest_payment": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "canceled_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     }
    }
   },
   "Invoice": {
    "type": "object",
    "required": [
     "id",
     "object",
     "livemode",
     "number",
     "customer",
     "status",
     "currency",
     "items",
     "total",
     "created_at"
    ],
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "object": {
      "const": "invoice"
     },
     "livemode": {
      "type": "boolean"
     },
     "number": {
      "type": "string",
      "example": "INV-000042"
     },
     "customer": {
      "type": "string",
      "format": "uuid"
     },
     "brand": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "status": {
      "type": "string",
      "enum": [
       "draft",
       "open",
       "paid",
       "void"
      ]
     },
     "currency": {
      "$ref": "#/components/schemas/Currency"
     },
     "items": {
      "type": "array",
      "items": {
       "type": "object",
       "required": [
        "description",
        "quantity",
        "unit_amount",
        "amount"
       ],
       "properties": {
        "description": {
         "type": "string"
        },
        "quantity": {
         "type": "integer"
        },
        "unit_amount": {
         "type": "integer"
        },
        "amount": {
         "type": "integer"
        }
       }
      }
     },
     "total": {
      "$ref": "#/components/schemas/Amount"
     },
     "due_date": {
      "type": [
       "string",
       "null"
      ],
      "format": "date"
     },
     "memo": {
      "type": [
       "string",
       "null"
      ]
     },
     "payment_intent": {
      "type": [
       "string",
       "null"
      ],
      "format": "uuid"
     },
     "hosted_invoice_url": {
      "type": "string",
      "description": "The customer's pay link. Present while the invoice is open (from finalize onwards, on every read); gone once paid or void."
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "finalized_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "paid_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "voided_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     }
    }
   }
  },
  "headers": {
   "IdempotentReplayed": {
    "description": "`true` when this response is a replay of an earlier request with the same Idempotency-Key.",
    "schema": {
     "type": "string",
     "enum": [
      "true",
      "false"
     ]
    }
   }
  },
  "responses": {
   "BadRequest": {
    "description": "Invalid request",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "error": {
        "type": "invalid_request_error",
        "code": "parameter_invalid",
        "message": "amount: Number must be greater than 0",
        "param": "amount"
       }
      }
     }
    }
   },
   "Unauthorized": {
    "description": "Missing or invalid API key",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "error": {
        "type": "authentication_error",
        "code": "invalid_api_key",
        "message": "Invalid or missing API key."
       }
      }
     }
    }
   },
   "Conflict": {
    "description": "The object is in a state that doesn't allow this",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "error": {
        "type": "state_error",
        "code": "payment_intent_unexpected_state",
        "message": "Cannot cancel a payment intent with status successful."
       }
      }
     }
    }
   },
   "IdempotencyConflict": {
    "description": "Idempotency-Key reused with a different request",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "error": {
        "type": "idempotency_error",
        "code": "idempotency_key_reused",
        "message": "This Idempotency-Key was already used with a different request."
       }
      }
     }
    }
   },
   "NotFound": {
    "description": "Not found, or not visible to this key",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      },
      "example": {
       "error": {
        "type": "invalid_request_error",
        "code": "resource_missing",
        "message": "No such payment intent."
       }
      }
     }
    }
   }
  },
  "securitySchemes": {
   "apiKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "A secret key: `bp_test_…` or `bp_live_…`. Server-side only; never ship it to a browser in live mode."
   }
  }
 }
}
