> ## Documentation Index
> Fetch the complete documentation index at: https://www.bitnob.dev/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Bitnob API requests authenticate with an `X-Auth-Client` API key header against https://api.bitnob.com.
> Always use the sandbox environment for testing. Never put live API keys in sample code.
> Money amounts are integers in the smallest unit of the currency (satoshis for BTC, cents for fiat). Never use floats.
> Every state-changing request takes a client-supplied `reference` and must be treated as idempotent on retry.
> Quotes expire. Re-quote rather than reusing a stale quote id.

# List customers

> Lists your customers, newest first, with optional filters. To get the next page, pass next_cursor as after.



## OpenAPI

````yaml /api-collections/swagger/bitnob-api-v2.openapi.json get /api/customers
openapi: 3.1.0
info:
  description: >-
    The Bitnob API for businesses: customers, virtual accounts, cards, payouts,
    crypto addresses and transfers, Lightning, trading and exchange rates.


    ## Authentication

    Every request is signed with your API key's client id and secret.


    **Signed requests (recommended).** Send:

    - `X-Auth-Client`: your client id

    - `X-Auth-Timestamp`: the current Unix time in seconds; requests more than 5
    minutes off are refused

    - `X-Auth-Nonce`: a unique random string for this request

    - `X-Auth-Signature`: hex HMAC-SHA256 of
    `{client_id}:{timestamp}:{nonce}:{body}` using your secret, where body is
    the raw request body (empty for GET)


    **Secret mode.** Send `X-Auth-Client` and `X-Auth-Secret` instead. Simpler,
    but the secret travels with every request.


    Live keys work only for an active organisation; sandbox keys work at any
    time. `ANY /api/whoami` echoes the authenticated client and is the quickest
    way to check your signing.


    ## Responses

    Successful responses are wrapped in an envelope with `success`, `message`,
    `data` and, on lists, `metadata`. Errors come either as the envelope with
    `success: false` and an `error` object, or as an RFC 7807 problem with a
    machine-readable `code`; branch on the code.


    Every response carries an `X-Correlation-ID` header; errors repeat it as
    `request_id`. Quote it to support.



    Every request passes a per-IP rate limit of 500 requests a minute (429 with
    `Retry-After`).



    This document is maintained by hand and checked against the route table on
    every build: every /api route is listed here.
  title: Bitnob API
  version: 1.0.0
servers:
  - description: Production
    url: https://api.bitnob.com
security:
  - BitnobClientId: []
    BitnobClientSecret: []
tags:
  - description: Check that your requests are signed correctly.
    name: Authentication
  - description: >-
      The people and businesses you serve. Creating and editing them needs the
      customers feature.
    name: Customers
  - description: >-
      Naira accounts that receive bank transfers, for your company or for a
      customer.
    name: Virtual accounts
  - description: Crypto deposit addresses, for your company or for a customer.
    name: Addresses
  - description: >-
      Virtual cards: issue, fund, withdraw, freeze, terminate, and the card KYC
      and corporate onboarding behind them.
    name: Cards
  - description: 'Pay out to bank accounts and mobile money: quote, initialize, finalize.'
    name: Payouts
  - description: Saved payout recipients.
    name: Beneficiaries
  - description: Banks and account lookups for payouts.
    name: Banks
  - description: Balance transfers between Bitnob organisations.
    name: Transfers
  - description: Crypto withdrawals.
    name: Withdrawals
  - description: Lightning invoices and payments.
    name: Lightning
  - description: Lightning addresses, LNURL withdraw links and LNURL payments.
    name: LNURL
  - description: Blockchain node access.
    name: Nodes
  - description: Quotes and orders for buying and selling.
    name: Trading
  - description: Rates and conversions.
    name: Exchange rates
  - description: Your transaction history.
    name: Transactions
  - description: Wallet balances.
    name: Balances
paths:
  /api/customers:
    get:
      tags:
        - Customers
      summary: List customers
      description: >-
        Lists your customers, newest first, with optional filters. To get the
        next page, pass next_cursor as after.
      operationId: customersList
      parameters:
        - description: >-
            Page size. limit is accepted as an alias. Values below 1 use the
            default; values above 50 are capped at 50.
          example: 20
          in: query
          name: page_size
          schema:
            default: 20
            maximum: 50
            minimum: 1
            type: integer
        - description: Alias for page_size.
          example: 20
          in: query
          name: limit
          schema:
            default: 20
            maximum: 50
            minimum: 1
            type: integer
        - description: Opaque cursor from the previous page's next_cursor.
          example: >-
            eyJ0aW1lc3RhbXAiOiIyMDI2LTEwLTI3VDEwOjMxOjQ1LjEyWiIsImlkIjoiMDE5YTNjMTEifQ
          in: query
          name: after
          schema:
            type: string
        - description: Alias for after.
          example: >-
            eyJ0aW1lc3RhbXAiOiIyMDI2LTEwLTI3VDEwOjMxOjQ1LjEyWiIsImlkIjoiMDE5YTNjMTEifQ
          in: query
          name: cursor
          schema:
            type: string
        - description: Alias for after.
          example: >-
            eyJ0aW1lc3RhbXAiOiIyMDI2LTEwLTI3VDEwOjMxOjQ1LjEyWiIsImlkIjoiMDE5YTNjMTEifQ
          in: query
          name: next_cursor
          schema:
            type: string
        - example: adaeze.okafor@example.com
          in: query
          name: email
          schema:
            format: email
            type: string
          description: Filter by email address.
        - example: '8000000001'
          in: query
          name: phone_number
          schema:
            type: string
          description: Filter by phone number.
        - description: Comma-separated list of customer types.
          examples:
            one_type:
              summary: Businesses only
              value: business
            several:
              summary: Individuals and businesses
              value: individual,business
          in: query
          name: customer_type
          schema:
            example: individual,business
            type: string
        - example: Adaeze
          in: query
          name: first_name
          schema:
            type: string
          description: Filter by first name.
        - example: Okafor
          in: query
          name: last_name
          schema:
            type: string
          description: Filter by last name.
        - example: Acme Logistics Ltd
          in: query
          name: company_name
          schema:
            type: string
          description: Filter by company name.
        - description: Comma-separated list of country codes.
          example: NGA,GHA
          in: query
          name: country
          schema:
            type: string
        - description: Comma-separated list of ID document types.
          example: bvn,nin
          in: query
          name: id_type
          schema:
            type: string
        - example: Lekki
          in: query
          name: city
          schema:
            type: string
          description: Filter by city.
        - example: Lagos
          in: query
          name: state
          schema:
            type: string
          description: Filter by state.
        - example: true
          in: query
          name: is_active
          schema:
            type: boolean
          description: Filter by whether the customer is active.
        - description: Free-text search.
          example: okafor
          in: query
          name: search
          schema:
            maxLength: 255
            type: string
        - description: >-
            Creation-date window. When set it overrides start_date and end_date,
            except custom, which requires both.
          example: last_7_days
          in: query
          name: period
          schema:
            enum:
              - all_time
              - last_7_days
              - last_1_month
              - last_3_months
              - last_6_months
              - last_12_months
              - year_to_date
              - custom
            type: string
        - description: Start of the creation-date window, RFC 3339 or YYYY-MM-DD.
          example: '2026-10-01'
          in: query
          name: start_date
          schema:
            type: string
        - description: End of the creation-date window, RFC 3339 or YYYY-MM-DD.
          example: '2026-10-30T23:59:59Z'
          in: query
          name: end_date
          schema:
            type: string
      responses:
        '200':
          content:
            application/json:
              examples:
                first_page:
                  summary: A page with more to come
                  value:
                    data:
                      customers:
                        - card_counts:
                            active: 1
                            blocked: 0
                            frozen: 0
                            lite: 0
                            pending: 0
                            pending_termination: 0
                            prepaid_standard: 0
                            standard: 1
                            terminated: 0
                            total: 1
                          card_program_kyc:
                            - card_program: collateral
                              normalized_status: approved
                          city: Lekki
                          company_id: 019a3b5c-1a2b-7c3d-8e4f-5a6b7c8d9e01
                          country: NGA
                          created_at: '2026-10-28T14:02:11.482913Z'
                          created_by: 019a3b5c-2b3c-7d4e-9f50-6b7c8d9e0f12
                          customer_type: individual
                          date_of_birth: '1990-04-12'
                          dial_code: '+234'
                          email: adaeze.okafor@example.com
                          first_name: Adaeze
                          id: 019a3c10-5e6f-7a80-9b1c-2d3e4f5a6b70
                          id_number: '22200000000'
                          id_type: bvn
                          is_active: true
                          kyc_status: approved
                          last_name: Okafor
                          line1: 12 Admiralty Way
                          metadata: ''
                          phone_number: '8000000001'
                          postal_code: '106104'
                          state: Lagos
                          updated_at: '2026-10-29T08:12:40.004121Z'
                        - card_counts:
                            active: 0
                            blocked: 0
                            frozen: 0
                            lite: 0
                            pending: 0
                            pending_termination: 0
                            prepaid_standard: 0
                            standard: 0
                            terminated: 0
                            total: 0
                          card_program_kyc: []
                          city: Apapa
                          company_id: 019a3b5c-1a2b-7c3d-8e4f-5a6b7c8d9e01
                          company_name: Acme Logistics Ltd
                          country: NGA
                          created_at: '2026-10-27T10:31:45.120044Z'
                          created_by: 019a3b5c-2b3c-7d4e-9f50-6b7c8d9e0f12
                          customer_type: business
                          dial_code: '+234'
                          email: finance@acmelogistics.example.com
                          first_name: Tunde
                          id: 019a3c11-7a8b-7c9d-8e0f-1a2b3c4d5e61
                          is_active: true
                          kyc_status: ''
                          last_name: Bakare
                          line1: 4 Creek Road
                          metadata: ''
                          phone_number: '8000000002'
                          registration_number: RC0000001
                          state: Lagos
                          updated_at: '2026-10-27T10:31:45.120044Z'
                      has_more: true
                      next_cursor: >-
                        eyJ0aW1lc3RhbXAiOiIyMDI2LTEwLTI3VDEwOjMxOjQ1LjEyWiIsImlkIjoiMDE5YTNjMTEifQ
                      page_size: 2
                      prev_cursor: ''
                      total: 37
                    message: Customers retrieved successfully
                    success: true
                    timestamp: '2026-10-30T09:15:02.481Z'
                last_page:
                  summary: >-
                    The last page: next_cursor is empty; total omitted when not
                    measured
                  value:
                    data:
                      customers:
                        - card_counts:
                            active: 0
                            blocked: 0
                            frozen: 0
                            lite: 0
                            pending: 0
                            pending_termination: 0
                            prepaid_standard: 0
                            standard: 0
                            terminated: 0
                            total: 0
                          card_program_kyc: []
                          city: Apapa
                          company_id: 019a3b5c-1a2b-7c3d-8e4f-5a6b7c8d9e01
                          company_name: Acme Logistics Ltd
                          country: NGA
                          created_at: '2026-10-27T10:31:45.120044Z'
                          created_by: 019a3b5c-2b3c-7d4e-9f50-6b7c8d9e0f12
                          customer_type: business
                          dial_code: '+234'
                          email: finance@acmelogistics.example.com
                          first_name: Tunde
                          id: 019a3c11-7a8b-7c9d-8e0f-1a2b3c4d5e61
                          is_active: true
                          kyc_status: ''
                          last_name: Bakare
                          line1: 4 Creek Road
                          metadata: ''
                          phone_number: '8000000002'
                          registration_number: RC0000001
                          state: Lagos
                          updated_at: '2026-10-27T10:31:45.120044Z'
                      has_more: false
                      next_cursor: ''
                      page_size: 20
                      prev_cursor: >-
                        eyJ0aW1lc3RhbXAiOiIyMDI2LTEwLTI3VDEwOjMxOjQ1LjEyWiIsImlkIjoiMDE5YTNjMTEifQ
                    message: Customers retrieved successfully
                    success: true
                    timestamp: '2026-10-30T09:15:02.481Z'
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - properties:
                      data:
                        $ref: '#/components/schemas/CustomersCustomerList'
                    type: object
          description: OK
        '400':
          content:
            application/json:
              examples:
                invalid_cursor:
                  summary: The cursor does not decode
                  value:
                    code: VALIDATION_ERROR
                    correlation_id: req_019a3e21-4b6c-7d8e-9fa0-b1c2d3e4f5a6
                    detail: >-
                      invalid cursor: invalid cursor format: illegal base64 data
                      at input byte 4
                    request_id: req_019a3e21-4b6c-7d8e-9fa0-b1c2d3e4f5a6
                    status: 400
                    timestamp: '2026-10-30T09:15:02.481Z'
                    title: Validation Error
                    type: https://api.bitnob.com/errors/VALIDATION_ERROR
                unsupported_filter:
                  summary: id or reference was sent
                  value:
                    error:
                      code: BAD_REQUEST
                      message: >-
                        id and reference are not supported filters on this
                        endpoint; use GET /api/customers/{customerId} to fetch
                        one customer
                    request_id: req_019a3e21-4b6c-7d8e-9fa0-b1c2d3e4f5a6
                    success: false
                    timestamp: '2026-10-30T09:15:02.481Z'
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ErrorEnvelope'
                  - $ref: '#/components/schemas/Problem'
          description: A filter or cursor is invalid.
          headers:
            X-Correlation-ID:
              $ref: '#/components/headers/X-Correlation-ID'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          content:
            application/json:
              examples:
                client_inactive:
                  $ref: '#/components/examples/ClientInactive'
                ip_not_whitelisted:
                  $ref: '#/components/examples/IPNotWhitelisted'
                org_not_active_live:
                  $ref: '#/components/examples/OrgNotActiveLive'
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ErrorEnvelope'
                  - $ref: '#/components/schemas/Problem'
          description: >-
            Not allowed: the request's IP is not on the key's allowlist, the
            client is inactive, or a live key is used before the organisation is
            active (ORG_NOT_ACTIVE).
          headers:
            X-Correlation-ID:
              $ref: '#/components/headers/X-Correlation-ID'
        '408':
          $ref: '#/components/responses/RequestTimeout'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          content:
            application/json:
              examples:
                internal_error_unhandled:
                  summary: >-
                    An unexpected failure, including period=custom without both
                    dates
                  value:
                    code: INTERNAL_ERROR
                    correlation_id: req_019a3e21-4b6c-7d8e-9fa0-b1c2d3e4f5a6
                    detail: An internal server error occurred
                    request_id: req_019a3e21-4b6c-7d8e-9fa0-b1c2d3e4f5a6
                    status: 500
                    timestamp: '2026-10-30T09:15:02.481Z'
                    title: Internal Server Error
                    type: https://api.bitnob.com/errors/INTERNAL_ERROR
              schema:
                $ref: '#/components/schemas/Problem'
          description: Something failed on our side; safe to retry (INTERNAL_ERROR).
          headers:
            X-Correlation-ID:
              $ref: '#/components/headers/X-Correlation-ID'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  schemas:
    Envelope:
      description: >-
        Successful responses are wrapped in this envelope, and so are errors a
        handler answers itself (request body and field validation, some
        not-found and conflict cases, ORG_NOT_ACTIVE): success is false and
        error carries a code and message. Errors raised by authentication and by
        the services behind a handler are a Problem instead.
      properties:
        data:
          description: >-
            The payload; its shape is given per operation. Omitted when there is
            none.
        error:
          $ref: '#/components/schemas/ErrorInfo'
        message:
          description: Human-readable summary; omitted when empty.
          type: string
        metadata:
          $ref: '#/components/schemas/Pagination'
        request_id:
          description: >-
            Set on error envelopes: the request's correlation id (req_ followed
            by a UUID), the same value as the X-Correlation-ID response header.
            Quote it to support.
          type: string
        success:
          description: true on success
          type: boolean
        timestamp:
          description: When the response was written.
          format: date-time
          type: string
      required:
        - success
        - timestamp
      type: object
    CustomersCustomerList:
      properties:
        customers:
          items:
            $ref: '#/components/schemas/CustomersCustomer'
          type: array
        has_more:
          type: boolean
        next_cursor:
          description: Empty on the last page.
          type: string
        page_size:
          type: integer
        prev_cursor:
          type: string
        total:
          description: Size of the whole filtered list; present only when it was measured.
          type: integer
      required:
        - customers
        - page_size
        - next_cursor
        - prev_cursor
        - has_more
      type: object
    ErrorEnvelope:
      allOf:
        - $ref: '#/components/schemas/Envelope'
        - properties:
            success:
              const: false
          required:
            - error
          type: object
      description: >-
        The envelope as an error: success is false, error is set, data is
        absent.
    Problem:
      description: >-
        RFC 7807 problem. Returned when authentication fails and for errors
        raised by the services behind a handler (validation, domain refusals
        such as FEATURE_NOT_ENABLED or PRECONDITION_FAILED, partner outages);
        branch on code.
      properties:
        code:
          description: >-
            Machine-readable; branch on this, not on the status or the wording.
            For example VALIDATION_ERROR, UNAUTHORIZED, FORBIDDEN,
            FEATURE_NOT_ENABLED, PERSONAL_WORKSPACE_CUSTOMERS,
            TIER_PRODUCT_LOCKED, NOT_FOUND, DUPLICATE_KEY_ERROR, ALREADY_EXISTS,
            PRECONDITION_FAILED, INSUFFICIENT_FUNDS, TIER_LIMIT_REACHED,
            RATE_LIMIT_EXCEEDED, TIMEOUT, SERVICE_UNAVAILABLE,
            LIMITS_UNAVAILABLE, PLATFORM_PAUSED, INTERNAL_ERROR.
          type: string
        correlation_id:
          description: >-
            The request's correlation id, the same value as the X-Correlation-ID
            response header.
          type: string
        detail:
          description: >-
            What went wrong for this request, safe to show; internal and partner
            failures carry a generic sentence.
          type: string
        extensions:
          additionalProperties: true
          description: >-
            Code-specific facts, for example feature_key (FEATURE_NOT_ENABLED),
            field or field_violations (VALIDATION_ERROR), rail, window, limit,
            used, requested and remaining (TIER_LIMIT_REACHED), scope
            (PLATFORM_PAUSED).
          type: object
        instance:
          type: string
        request_id:
          description: Equal to correlation_id.
          type: string
        status:
          description: The HTTP status, repeated.
          type: integer
        timestamp:
          format: date-time
          type: string
        title:
          description: >-
            Short summary of the code, for example Validation Error or Feature
            Not Enabled.
          type: string
        type:
          description: https://api.bitnob.com/errors/{code}
          format: uri
          type: string
      required:
        - type
        - title
        - status
        - code
        - timestamp
      type: object
    ErrorInfo:
      properties:
        code:
          description: >-
            Machine-readable, for example BAD_REQUEST, NOT_FOUND, CONFLICT,
            ORG_NOT_ACTIVE, RATE_LIMIT_EXCEEDED, SERVICE_UNAVAILABLE,
            INTERNAL_ERROR.
          type: string
        details:
          additionalProperties: true
          description: >-
            For field validation, a map of field name to message ("email":
            "Email must be a valid email address"); for a body that does not
            decode, the offending field.
          type: object
        message:
          type: string
      required:
        - message
      type: object
    Pagination:
      description: >-
        List metadata. Page lists set page, per_page, total and total_pages;
        offset and cursor lists set limit, offset, has_more and next_cursor.
        Zero and empty fields are omitted, and metadata is absent when nothing
        is set.
      properties:
        has_more:
          type: boolean
        limit:
          type: integer
        next_cursor:
          description: Opaque; pass as cursor for the next page.
          type: string
        offset:
          type: integer
        page:
          type: integer
        per_page:
          type: integer
        total:
          type: integer
        total_pages:
          type: integer
      type: object
    CustomersCustomer:
      properties:
        card_counts:
          description: >-
            Null on create and update responses, or when counts could not be
            read.
          oneOf:
            - $ref: '#/components/schemas/CustomersCardCounts'
            - type: 'null'
        card_program_kyc:
          description: >-
            Present on get and list only; empty when no card-program KYC is on
            record.
          items:
            $ref: '#/components/schemas/CustomersCardProgramKYC'
          type: array
        city:
          type: string
        company_id:
          format: uuid
          type: string
        company_name:
          type: string
        country:
          type: string
        created_at:
          format: date-time
          type: string
        created_by:
          format: uuid
          type: string
        customer_type:
          example: individual
          type: string
        date_of_birth:
          format: date
          type: string
        dial_code:
          type: string
        email:
          format: email
          type: string
        first_name:
          type: string
        id:
          format: uuid
          type: string
        id_number:
          type: string
        id_type:
          type: string
        is_active:
          type: boolean
        kyc_status:
          description: Empty when nothing has been submitted.
          type: string
        last_name:
          type: string
        line1:
          type: string
        metadata:
          description: Always an empty string.
          type: string
        phone_number:
          type: string
        postal_code:
          type: string
        registration_number:
          type: string
        state:
          type: string
        updated_at:
          format: date-time
          type: string
      required:
        - id
        - company_id
        - email
        - customer_type
        - metadata
        - is_active
        - kyc_status
        - card_counts
        - created_by
        - created_at
        - updated_at
      type: object
    CustomersCardCounts:
      description: >-
        Cards held by the customer, by status and type. Terminated is outside
        total.
      properties:
        active:
          format: int32
          type: integer
        blocked:
          format: int32
          type: integer
        frozen:
          format: int32
          type: integer
        lite:
          format: int32
          type: integer
        pending:
          format: int32
          type: integer
        pending_termination:
          format: int32
          type: integer
        prepaid_standard:
          format: int32
          type: integer
        standard:
          format: int32
          type: integer
        terminated:
          format: int32
          type: integer
        total:
          format: int32
          type: integer
      type: object
    CustomersCardProgramKYC:
      properties:
        card_program:
          example: collateral
          type: string
        normalized_status:
          description: >-
            Normalised KYC status, for example none, initiated, pending,
            approved, rejected, expired, rejected_incomplete.
          example: approved
          type: string
      type: object
  headers:
    X-Correlation-ID:
      description: >-
        Generated for every request (any value the client sends is ignored);
        quote it to support. Errors repeat it as request_id and correlation_id.
      example: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
      schema:
        type: string
    Retry-After:
      description: Seconds to wait before retrying.
      example: 1
      schema:
        minimum: 0
        type: integer
    X-RateLimit-Limit:
      description: Requests allowed per window by the per-IP limiter (500 a minute).
      example: 500
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests left in the current window.
      example: 0
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Seconds until the window resets.
      example: 37
      schema:
        type: integer
  responses:
    Unauthorized:
      content:
        application/json:
          examples:
            unauthorized_auth_failed:
              $ref: '#/components/examples/UnauthorizedAuthFailed'
            unauthorized_invalid_secret:
              $ref: '#/components/examples/UnauthorizedInvalidSecret'
            unauthorized_invalid_signature:
              $ref: '#/components/examples/UnauthorizedInvalidSignature'
            unauthorized_locked_out:
              $ref: '#/components/examples/UnauthorizedLockedOut'
          schema:
            $ref: '#/components/schemas/Problem'
      description: >-
        Authentication failed: a signing header is missing or malformed, the
        timestamp is more than 5 minutes off, the signature or secret is wrong,
        or the client is locked out after failed checks (UNAUTHORIZED).
      headers:
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
    RequestTimeout:
      content:
        application/json:
          examples:
            request_timeout:
              $ref: '#/components/examples/RequestTimeout'
          schema:
            $ref: '#/components/schemas/Problem'
      description: >-
        The request ran past its deadline (TIMEOUT); retry, with the same
        reference for writes.
      headers:
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
    TooManyRequests:
      content:
        application/json:
          examples:
            rate_limited:
              $ref: '#/components/examples/RateLimited'
            rate_limited_envelope:
              $ref: '#/components/examples/RateLimitedEnvelope'
          schema:
            oneOf:
              - $ref: '#/components/schemas/ErrorEnvelope'
              - $ref: '#/components/schemas/Problem'
      description: >-
        Rate limited. The per-IP limiter (500 requests a minute) answers with a
        Problem and Retry-After; operation-specific throttles answer with the
        envelope.
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
    ServiceUnavailable:
      content:
        application/json:
          examples:
            auth_service_busy:
              $ref: '#/components/examples/AuthServiceBusy'
            auth_service_unavailable:
              $ref: '#/components/examples/AuthServiceUnavailable'
            limits_unavailable:
              $ref: '#/components/examples/LimitsUnavailable'
            platform_paused:
              $ref: '#/components/examples/PlatformPaused'
            partner_unavailable:
              $ref: '#/components/examples/PartnerUnavailable'
            service_unavailable_envelope:
              $ref: '#/components/examples/ServiceUnavailableEnvelope'
          schema:
            oneOf:
              - $ref: '#/components/schemas/ErrorEnvelope'
              - $ref: '#/components/schemas/Problem'
      description: >-
        Temporarily unavailable; retry later. The identity service could not
        check the credentials (sent with Retry-After), a partner is down
        (SERVICE_UNAVAILABLE), the limits check could not run
        (LIMITS_UNAVAILABLE), or a platform control paused money movement
        (PLATFORM_PAUSED).
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
        X-Correlation-ID:
          $ref: '#/components/headers/X-Correlation-ID'
  examples:
    ClientInactive:
      summary: The API key's client is deactivated
      value:
        code: FORBIDDEN
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Client account is inactive
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 403
        timestamp: '2026-10-30T09:15:02Z'
        title: Forbidden
        type: https://api.bitnob.com/errors/FORBIDDEN
    IPNotWhitelisted:
      summary: The request came from an IP not on the key's allowlist
      value:
        code: FORBIDDEN
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: IP address not whitelisted
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 403
        timestamp: '2026-10-30T09:15:02Z'
        title: Forbidden
        type: https://api.bitnob.com/errors/FORBIDDEN
    OrgNotActiveLive:
      description: Sandbox keys are never refused this way.
      summary: A live key on an organisation that is not active yet
      value:
        error:
          code: ORG_NOT_ACTIVE
          message: >-
            Your business isn't active yet, so live isn't available. Use your
            sandbox keys until it's activated.
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        success: false
        timestamp: '2026-10-30T09:15:02.481Z'
    UnauthorizedAuthFailed:
      description: >-
        Returned when X-Auth-Client, X-Auth-Timestamp, X-Auth-Nonce or
        X-Auth-Signature is missing, the nonce is not 8 to 128 characters, the
        signature is not hex, or the timestamp is more than 5 minutes from the
        server's clock. The detail does not say which; check each.
      summary: A signing header is missing or malformed, or the timestamp is stale
      value:
        code: UNAUTHORIZED
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Authentication failed
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 401
        timestamp: '2026-10-30T09:15:02Z'
        title: Unauthorized
        type: https://api.bitnob.com/errors/UNAUTHORIZED
    UnauthorizedInvalidSecret:
      summary: 'Secret mode: the client id or secret is wrong'
      value:
        code: UNAUTHORIZED
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Invalid credentials
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 401
        timestamp: '2026-10-30T09:15:02Z'
        title: Unauthorized
        type: https://api.bitnob.com/errors/UNAUTHORIZED
    UnauthorizedInvalidSignature:
      description: >-
        The detail is the identity service's reason when it gives one (an
        unknown client or a reused nonce reads differently); Invalid signature
        otherwise.
      summary: The signature does not match
      value:
        code: UNAUTHORIZED
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Invalid signature
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 401
        timestamp: '2026-10-30T09:15:02Z'
        title: Unauthorized
        type: https://api.bitnob.com/errors/UNAUTHORIZED
    UnauthorizedLockedOut:
      summary: Too many failed credential checks
      value:
        code: UNAUTHORIZED
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Too many failed credential checks; retry later
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 401
        timestamp: '2026-10-30T09:15:02Z'
        title: Unauthorized
        type: https://api.bitnob.com/errors/UNAUTHORIZED
    RequestTimeout:
      summary: The request ran past its deadline
      value:
        code: TIMEOUT
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: The request took too long to complete. Please try again.
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 408
        timestamp: '2026-10-30T09:15:02Z'
        title: Request Timeout
        type: https://api.bitnob.com/errors/TIMEOUT
    RateLimited:
      summary: The per-IP limit (500 requests a minute) is reached
      value:
        code: RATE_LIMIT_EXCEEDED
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Too many requests. Please try again later.
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 429
        timestamp: '2026-10-30T09:15:02Z'
        title: Rate Limit Exceeded
        type: https://api.bitnob.com/errors/RATE_LIMIT_EXCEEDED
    RateLimitedEnvelope:
      summary: An operation-specific throttle (answered by the handler)
      value:
        error:
          code: RATE_LIMIT_EXCEEDED
          message: >-
            a verification link was sent to this customer in the last minute;
            try again shortly
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        success: false
        timestamp: '2026-10-30T09:15:02.481Z'
    AuthServiceBusy:
      description: 'Sent with Retry-After: 1.'
      summary: Too many large signed bodies are being checked at once
      value:
        code: SERVICE_UNAVAILABLE
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Authentication service is busy, retry shortly
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 503
        timestamp: '2026-10-30T09:15:02Z'
        title: Service Unavailable
        type: https://api.bitnob.com/errors/SERVICE_UNAVAILABLE
    AuthServiceUnavailable:
      description: 'Sent with Retry-After: 1. The detail is worded exactly like this today.'
      summary: The identity service could not be reached to check the credentials
      value:
        code: SERVICE_UNAVAILABLE
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Service Authentication service unavailable is currently unavailable
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 503
        timestamp: '2026-10-30T09:15:02Z'
        title: Service Unavailable
        type: https://api.bitnob.com/errors/SERVICE_UNAVAILABLE
    LimitsUnavailable:
      summary: The tier limit check could not run
      value:
        code: LIMITS_UNAVAILABLE
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: >-
          We could not verify your account limits right now. Please try again
          shortly.
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 503
        timestamp: '2026-10-30T09:15:02Z'
        title: Limits Unavailable
        type: https://api.bitnob.com/errors/LIMITS_UNAVAILABLE
    PlatformPaused:
      summary: Money movement is paused by a platform control
      value:
        code: PLATFORM_PAUSED
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: >-
          Money movement is temporarily paused. Nothing is lost — requests can
          be retried once the pause lifts.
        extensions:
          scope: asset:BTC
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 503
        timestamp: '2026-10-30T09:15:02Z'
        title: Money Movement Paused
        type: https://api.bitnob.com/errors/PLATFORM_PAUSED
    PartnerUnavailable:
      summary: A partner or internal service is unavailable
      value:
        code: SERVICE_UNAVAILABLE
        correlation_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        detail: Service is temporarily unavailable. Please try again later.
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        status: 503
        timestamp: '2026-10-30T09:15:02Z'
        title: Service Unavailable
        type: https://api.bitnob.com/errors/SERVICE_UNAVAILABLE
    ServiceUnavailableEnvelope:
      summary: Unavailable (answered by the handler)
      value:
        error:
          code: SERVICE_UNAVAILABLE
          message: LNURL payments are temporarily disabled
        request_id: req_019a3b5c-7d1e-7f20-8a4b-3c5d6e7f8091
        success: false
        timestamp: '2026-10-30T09:15:02.481Z'
  securitySchemes:
    BitnobClientId:
      type: apiKey
      in: header
      name: X-Auth-Client
      description: |
        Your workspace client id.

        All calls must include four headers:
        - `X-Auth-Client`   — your workspace client id
        - `X-Auth-Timestamp` — Unix seconds
        - `X-Auth-Nonce`    — 16-byte random hex
        - `X-Auth-Signature` — hex(HMAC-SHA256(
          `{client_id}:{timestamp}:{nonce}:{raw_body}`,
          client_secret))

        The playground computes the timestamp, nonce and signature for you.
    BitnobClientSecret:
      type: apiKey
      in: header
      name: X-Playground-Client-Secret
      description: >
        Your sandbox client secret. The playground uses it to sign the request
        in your browser and removes it before the request is sent. Never send
        your client secret as a header in your own integration.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.