---
openapi: 3.1.0
info:
  title: Lumepay API
  description: |
    Lumepay API documentation.

    The Lumepay API gives third-party partners secure server-to-server access to accounts, wallets, currencies, beneficiaries, and deposits
    and review payment activity. Use this API
    to build operational dashboards, initiate supported money movement workflows, reconcile
    transactions, and surface account or wallet information in your own internal systems.

    This documentation describes the external `v1` API contract and the conventions your integration
    should follow from its first request through production use.

    ## Authentication and access

    API requests must include both `X-API-KEY` and `X-API-SECRET` headers. API keys are created
    through the authenticated user's API key management flow. The same user can revoke or rotate those
    credentials when needed. Treat the API secret as a server-side credential only; never expose it in
    browser, mobile, or other client-side code.

    Authentication and access failures are handled consistently across the external API:

    - `401` means the request could not be authenticated because API key headers are missing, invalid,
      revoked, or expired.
    - `403` means the request was authenticated, but the API key owner is not allowed to perform the
      action because of permissions, account state, or access rules.

    Individual endpoint documentation does not repeat these responses unless an endpoint has
    authentication or access behavior that differs from the standard API key flow.

    ## Currencies and payment routes

    Supported currencies and payment routes are configuration-driven. When building forms or validation
    rules, use the relevant external, public, or user currency endpoints instead of hard-coding supported
    currency lists from this document. External account and currency endpoints are scoped to the API key
    owner's effective jurisdiction.


    ## Security

    Production and staging integrations must use HTTPS. Rotate API keys immediately if you suspect a
    secret has been exposed. Store secrets in a vault or server-side secret manager, and do not log full
    API secrets.

    ## Error model

    Error responses use Lumepay's standard error envelope:

    ```json
    {
      "code": 1133,
      "message": "Validation error: amount is required",
      "httpStatus": 400,
      "requestId": "req_01HY...",
      "timestamp": "2026-01-01T00:00:00Z",
      "errors": [
        {
          "field": "amount",
          "message": "must be greater than 0"
        }
      ]
    }
    ```

    Common non-authentication error classes include `400` validation failures, `404` resources not found
    for the authenticated owner, `409` insufficient funds or conflicting money movement state, and `500`
    unexpected server errors.

    ## Pagination and filtering

    Current list endpoints may expose reserved query parameters for page, size, sort, date range, and
    status filters. Unless an endpoint explicitly says otherwise, current responses are unpaginated arrays
    and your integration should not depend on server-side pagination behavior yet.

    ## Transaction lifecycle

    Deposits move through domain statuses such as pending, processing,
    completed, failed, cancelled, or reversed depending on the resource type. A status is final only when
    the specific endpoint and business flow represent it as terminal. Your integration can use webhook
    subscriptions for supported lifecycle notifications, and should continue to treat the read endpoints
    as the source of truth for current resource state.

    This is version v1 of this API documentation. Last update on June 15, 2026.
  contact:
    name: Lume Forge
  version: v1
servers:
- url: "/"
tags:
- name: Beneficiaries
  description: Beneficiary endpoints for the authenticated API key owner.
- name: Accounts
  description: Account endpoints for the authenticated API key owner.
- name: Deposits
  description: Deposit history endpoints for the authenticated API key owner.
- name: Webhooks
  description: Webhook event catalog and subscription management endpoints.
- name: Wallets
  description: Wallet endpoints for the authenticated API key owner.
- name: Currencies
  description: Currency catalog endpoints for the authenticated API key owner.
paths:
  "/api/v1/webhooks/subscriptions":
    get:
      tags:
      - Webhooks
      summary: List webhook subscriptions
      description: Returns webhook subscriptions owned by the authenticated API key
        owner.
      operationId: listSubscriptions
      parameters:
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Webhook subscriptions returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  "$ref": "#/components/schemas/WebhookSubscriptionResponse"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
    post:
      tags:
      - Webhooks
      summary: Create webhook subscription
      description: Creates a pending webhook subscription for the authenticated API
        key owner. The target URL must be a public HTTPS callback URL and at least
        one supported event type is required.
      operationId: createSubscription
      parameters:
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/WebhookSubscriptionCreateRequest"
        required: true
      responses:
        '201':
          description: Webhook subscription created successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/WebhookSubscriptionResponse"
        '400':
          "$ref": "#/components/responses/BadRequestError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
  "/api/v1/webhooks/subscriptions/{subscriptionId}/verify":
    post:
      tags:
      - Webhooks
      operationId: verifySubscription
      parameters:
      - name: subscriptionId
        in: path
        required: true
        schema:
          type: string
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/WebhookSubscriptionResponse"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/webhooks/subscriptions/{subscriptionId}/deactivate":
    post:
      tags:
      - Webhooks
      summary: Deactivate webhook subscription
      description: Deactivates a webhook subscription owned by the authenticated API
        key owner.
      operationId: deactivateSubscription
      parameters:
      - name: subscriptionId
        in: path
        description: Webhook subscription id returned when the subscription was created.
        required: true
        schema:
          type: string
        example: whsub_5e737a5abaee46568bd8d530b9b3521a
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Webhook subscription deactivated successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/WebhookSubscriptionResponse"
        '400':
          "$ref": "#/components/responses/BadRequestError"
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
  "/api/v1/webhooks/subscriptions/{subscriptionId}/activate":
    post:
      tags:
      - Webhooks
      summary: Activate webhook subscription
      description: Activates a verified webhook subscription owned by the authenticated
        API key owner.
      operationId: activateSubscription
      parameters:
      - name: subscriptionId
        in: path
        description: Webhook subscription id returned when the subscription was created.
        required: true
        schema:
          type: string
        example: whsub_5e737a5abaee46568bd8d530b9b3521a
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Webhook subscription activated successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/WebhookSubscriptionResponse"
        '400':
          "$ref": "#/components/responses/BadRequestError"
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
  "/api/v1/accounts":
    get:
      tags:
      - Accounts
      summary: List accounts
      description: Returns accounts belonging to the authenticated API key owner for
        currencies enabled in the owner's effective jurisdiction.
      operationId: getAccounts
      parameters:
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Accounts returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  "$ref": "#/components/schemas/ExternalAccountResponse"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
    post:
      tags:
      - Accounts
      summary: Create account
      description: Creates an account for the authenticated API key owner only when
        the requested currency is enabled in the owner's effective jurisdiction.
      operationId: createAccount
      parameters:
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ExternalCreateAccountRequest"
        required: true
      responses:
        '201':
          description: Account created successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ExternalAccountResponse"
        '400':
          "$ref": "#/components/responses/BadRequestError"
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '409':
          "$ref": "#/components/responses/ConflictError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
  "/api/v1/webhooks/subscriptions/{subscriptionId}":
    get:
      tags:
      - Webhooks
      summary: Get webhook subscription
      description: Returns one webhook subscription owned by the authenticated API
        key owner.
      operationId: getSubscription
      parameters:
      - name: subscriptionId
        in: path
        description: Webhook subscription id returned when the subscription was created.
        required: true
        schema:
          type: string
        example: whsub_5e737a5abaee46568bd8d530b9b3521a
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Webhook subscription returned successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/WebhookSubscriptionResponse"
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/webhooks/events":
    get:
      tags:
      - Webhooks
      summary: List webhook events
      description: Returns the active webhook event types the authenticated API key
        owner can subscribe to.
      operationId: listEvents
      parameters:
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Webhook events returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  "$ref": "#/components/schemas/WebhookEventResponse"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/wallets":
    get:
      tags:
      - Wallets
      summary: List wallets
      description: Returns wallets belonging to the authenticated API key owner.
      operationId: getWallets
      parameters:
      - name: paymentMethodType
        in: query
        description: Optional payment method type filter for fiat wallets.
        required: false
        schema:
          type: string
        example: EFT
      - name: networkName
        in: query
        description: Optional network name filter for crypto wallets.
        required: false
        schema:
          type: string
        example: Ethereum (ETH)
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Wallets returned successfully
          content:
            application/json:
              examples:
                Fiat virtual EFT wallet:
                  summary: Fiat wallet with user-specific EFT bank account details
                  description: Fiat virtual EFT wallet
                  value:
                  - id: wal_3Q8M1K
                    currency: ZAR
                    depositDetails:
                      bankName: Nedbank
                      accountName: Example Customer
                      accountNumber: '9876543210'
                      accountType: Current
                      branchCode: '198765'
                    networkName:
                    paymentMethodType: EFT
                Crypto wallet:
                  summary: Crypto wallet with blockchain address deposit details
                  description: Crypto wallet
                  value:
                  - id: wal_7K9Q2M
                    currency: BTC
                    depositDetails:
                      address: bc1qexample...
                      address_tag: '123456'
                    networkName: Bitcoin
                    paymentMethodType:
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/wallets/{walletId}":
    get:
      tags:
      - Wallets
      summary: Get wallet
      description: Returns one wallet belonging to the authenticated API key owner.
      operationId: getWallet
      parameters:
      - name: walletId
        in: path
        description: Wallet id returned by the wallet list endpoint.
        required: true
        schema:
          type: string
        example: wal_3Q8M1K
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Wallet returned successfully
          content:
            application/json:
              examples:
                Fiat virtual EFT wallet:
                  summary: Fiat wallet with user-specific EFT bank account details
                  description: Fiat virtual EFT wallet
                  value:
                    id: wal_3Q8M1K
                    currency: ZAR
                    depositDetails:
                      bankName: Nedbank
                      accountName: Example Customer
                      accountNumber: '9876543210'
                      accountType: Current
                      branchCode: '198765'
                    networkName:
                    paymentMethodType: EFT
                Crypto wallet:
                  summary: Crypto wallet with blockchain address deposit details
                  description: Crypto wallet
                  value:
                    id: wal_7K9Q2M
                    currency: BTC
                    depositDetails:
                      address: bc1qexample...
                      address_tag: '123456'
                    networkName: Bitcoin
                    paymentMethodType:
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/deposits":
    get:
      tags:
      - Deposits
      summary: List deposits
      description: Returns the authenticated user's deposit history. Pagination, sorting,
        date filtering, and status filtering parameters are reserved for this list
        endpoint; current responses remain unpaginated until server-side pagination
        is enabled.
      operationId: depositHistory
      parameters:
      - name: page
        in: query
        description: Page number, zero-based.
        required: false
        schema:
          type: integer
          format: int32
        example: 0
      - name: size
        in: query
        description: 'Page size. Planned maximum: 100.'
        required: false
        schema:
          type: integer
          format: int32
        example: 50
      - name: sort
        in: query
        description: 'Sort expression: field,direction.'
        required: false
        schema:
          type: string
        example: completedAt,desc
      - name: dateFrom
        in: query
        description: Lower timestamp bound.
        required: false
        schema:
          type: string
          format: date-time
        example: '2026-01-01T00:00:00Z'
      - name: dateTo
        in: query
        description: Upper timestamp bound.
        required: false
        schema:
          type: string
          format: date-time
        example: '2026-01-31T23:59:59Z'
      - name: status
        in: query
        description: Deposit status filter.
        required: false
        schema:
          type: string
        example: COMPLETED
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Deposits returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  "$ref": "#/components/schemas/DepositResponse"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/deposits/{transactionId}":
    get:
      tags:
      - Deposits
      summary: Get deposit
      description: Returns a single deposit belonging to the authenticated API key
        owner.
      operationId: getDeposit
      parameters:
      - name: transactionId
        in: path
        description: Deposit Transaction id returned by the deposit list endpoint.
        required: true
        schema:
          type: string
        example: dep_9H2K7P
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Deposit returned successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/DepositResponse"
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/currencies":
    get:
      tags:
      - Currencies
      summary: List currencies
      description: Returns enabled currencies for the authenticated API key owner's
        effective jurisdiction.
      operationId: getCurrencies
      parameters:
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Currencies returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  "$ref": "#/components/schemas/ExternalCurrencyResponse"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/beneficiaries":
    get:
      tags:
      - Beneficiaries
      summary: List beneficiaries
      description: Returns confirmed beneficiaries belonging to the authenticated
        API key owner.
      operationId: getBeneficiaries
      parameters:
      - name: currency
        in: query
        description: Optional beneficiary currency code filter.
        required: false
        schema:
          type: string
        example: ZAR
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Beneficiaries returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  "$ref": "#/components/schemas/BeneficiaryResponse"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/beneficiaries/{beneficiaryId}":
    get:
      tags:
      - Beneficiaries
      summary: Get beneficiary
      description: Returns a confirmed beneficiary belonging to the authenticated
        API key owner.
      operationId: getBeneficiary
      parameters:
      - name: beneficiaryId
        in: path
        description: Beneficiary id returned by the beneficiary list endpoint.
        required: true
        schema:
          type: string
        example: ben_7K9Q2M
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Beneficiary returned successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/BeneficiaryResponse"
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/accounts/{accountId}":
    get:
      tags:
      - Accounts
      summary: Get account
      description: Returns one account belonging to the authenticated API key owner
        when its currency is enabled in the owner's effective jurisdiction.
      operationId: getAccount
      parameters:
      - name: accountId
        in: path
        description: Account id returned by the account list endpoint.
        required: true
        schema:
          type: string
        example: acc_8F4J2N
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Account returned successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ExternalAccountResponse"
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
  "/api/v1/accounts/currency/{currency}":
    get:
      tags:
      - Accounts
      summary: Get account by currency
      description: Returns one account belonging to the authenticated API key owner
        for the requested currency when that currency is enabled in the owner's effective
        jurisdiction.
      operationId: getAccountByCurrency
      parameters:
      - name: currency
        in: path
        description: Currency for the account lookup.
        required: true
        schema:
          type: string
        example: ZAR
      - name: X-API-KEY
        in: header
        description: Public API key issued from the Lumepay API key management flow.
        required: true
        schema:
          type: string
      - name: X-API-SECRET
        in: header
        description: API secret paired with the public API key.
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Account returned successfully
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ExternalAccountResponse"
        '404':
          "$ref": "#/components/responses/NotFoundError"
        '403':
          "$ref": "#/components/responses/ForbiddenError"
        '500':
          "$ref": "#/components/responses/InternalServerError"
        '401':
          "$ref": "#/components/responses/UnauthorizedError"
        '400':
          "$ref": "#/components/responses/BadRequestError"
components:
  schemas:
    WebhookSubscriptionCreateRequest:
      type: object
      properties:
        name:
          type: string
        targetUrl:
          type: string
        eventTypes:
          type: array
          items:
            type: string
          minItems: 1
          uniqueItems: true
    WebhookEventResponse:
      type: object
      properties:
        eventType:
          type: string
        resourceType:
          type: string
        event:
          type: string
        displayName:
          type: string
        description:
          type: string
    WebhookSubscriptionResponse:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        targetUrl:
          type: string
        status:
          type: string
        events:
          type: array
          items:
            "$ref": "#/components/schemas/WebhookEventResponse"
        verifiedAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    ExternalCreateAccountRequest:
      type: object
      properties:
        currency:
          type: string
          description: Currency code for the account to create.
          example: ZAR
    ExternalAccountResponse:
      type: object
      properties:
        id:
          type: string
          description: Account id used by external account endpoints.
          example: acc_8F4J2N
        currency:
          type: string
          description: Account currency.
          example: ZAR
        balance:
          type: number
          description: Available account balance.
          example: 2500.0
        lockedBalance:
          type: number
          description: Locked account balance.
          example: 0.0
    JsonNode:
      type: object
      additionalProperties: true
      description: Raw withdrawal details stored as JSON object.
      example:
        bankName: FNB
        accountNumber: '1234567890'
      properties:
        pojo:
          type: boolean
        int:
          type: boolean
        double:
          type: boolean
        bigDecimal:
          type: boolean
        bigInteger:
          type: boolean
        nodeType:
          type: string
          enum:
          - ARRAY
          - BINARY
          - BOOLEAN
          - MISSING
          - 'NULL'
          - NUMBER
          - OBJECT
          - POJO
          - STRING
        long:
          type: boolean
        floatingPointNumber:
          type: boolean
        integralNumber:
          type: boolean
        valueNode:
          type: boolean
        missingNode:
          type: boolean
        string:
          type: boolean
        boolean:
          type: boolean
        textual:
          type: boolean
          deprecated: true
        short:
          type: boolean
        container:
          type: boolean
        object:
          type: boolean
        binary:
          type: boolean
        number:
          type: boolean
        array:
          type: boolean
        empty:
          type: boolean
        'null':
          type: boolean
        float:
          type: boolean
        embeddedValue:
          type: boolean
    DepositResponse:
      type: object
      description: Deposit transaction returned by the API.
      properties:
        currency:
          type: string
          description: Deposit currency code.
          example: USDT
        transactionId:
          type: string
          description: Transaction id for deposit lookups.
          example: DP9H2K7P
        amount:
          type: number
          description: Deposit amount.
          example: 100.0
        fee:
          type: number
          description: Deposit fee.
          example: 0.0
        status:
          type: string
          description: Deposit status.
          enum:
          - SUBMITTED
          - PENDING
          - PROCESSING
          - COMPLIANCE_PENDING
          - COMPLETED
          - FAILED
          - CANCELLED
          - REVERSED
          example: COMPLETED
        completedAt:
          type: string
          format: date-time
          description: Completion timestamp.
          example: '2026-05-11T10:15:30'
    ExternalCurrencyResponse:
      type: object
      properties:
        currency:
          type: string
          description: Currency code.
          example: ZAR
        name:
          type: string
          description: Currency display name.
          example: South African Rand
    BeneficiaryResponse:
      type: object
      description: Beneficiary available to the authenticated API key user.
      properties:
        id:
          type: string
          description: Beneficiary id used by external beneficiary endpoints.
          example: ben_7K9Q2M
        currency:
          type: string
          description: Saved beneficiary currency.
          example: ZAR
        nickname:
          type: string
          description: Beneficiary nickname.
          example: FNB Savings
        withdrawFormDetails:
          "$ref": "#/components/schemas/JsonNode"
          additionalProperties: true
          description: Saved withdrawal form details for the beneficiary.
          example:
            bankName: FNB
            accountNumber: '1234567890'
            accountHolderName: Jane Example
        createdAt:
          type: string
          format: date-time
          description: Beneficiary creation timestamp.
          example: '2026-05-11T10:15:30Z'
    ApiResponse:
      type: object
      properties:
        code:
          type: integer
          format: int32
          example: 400
        message:
          type: string
          example: Request validation failed
        httpStatus:
          type: integer
          format: int32
          example: 400
        requestId:
          type: string
          example: req_01HY0000000000000000000000
        timestamp:
          type: string
          format: date-time
          example: '2026-01-01T00:00:00Z'
        errors:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
                example: amount
              message:
                type: string
                example: must be greater than 0
  responses:
    NotFoundError:
      description: Resource was not found for the authenticated API key owner
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ApiResponse"
          example:
            errors: []
            timestamp: '2026-01-01T00:00:00Z'
            code: 404
            message: Resource was not found for the authenticated API key owner
            requestId: req_01HY0000000000000000000000
            httpStatus: 404
    ForbiddenError:
      description: Authenticated API key is not allowed to perform this action
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ApiResponse"
          example:
            errors: []
            timestamp: '2026-01-01T00:00:00Z'
            code: 403
            message: Authenticated API key is not allowed to perform this action
            requestId: req_01HY0000000000000000000000
            httpStatus: 403
    InternalServerError:
      description: Unexpected server error
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ApiResponse"
          example:
            errors: []
            timestamp: '2026-01-01T00:00:00Z'
            code: 500
            message: Unexpected server error
            requestId: req_01HY0000000000000000000000
            httpStatus: 500
    UnauthorizedError:
      description: API key authentication failed
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ApiResponse"
          example:
            errors: []
            timestamp: '2026-01-01T00:00:00Z'
            code: 401
            message: API key authentication failed
            requestId: req_01HY0000000000000000000000
            httpStatus: 401
    BadRequestError:
      description: Request validation failed
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ApiResponse"
          example:
            errors: []
            timestamp: '2026-01-01T00:00:00Z'
            code: 400
            message: Request validation failed
            requestId: req_01HY0000000000000000000000
            httpStatus: 400
    ConflictError:
      description: Request conflicts with current resource or money movement state
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/ApiResponse"
          example:
            errors: []
            timestamp: '2026-01-01T00:00:00Z'
            code: 409
            message: Request conflicts with current resource or money movement state
            requestId: req_01HY0000000000000000000000
            httpStatus: 409
