openapi: 3.0.3

info:
  title: Settlix Payment API
  version: 1.0.0
  description: |
    # Settlix Payment API

    Accept payments and process payouts through Settlix's unified API.

    ## Quick Start

    ### Step 1: Get Your API Keys

    Contact your Settlix account manager to receive:
    - **API Key** — for accepting payments (used in the `X-Api-Key` header)
    - **Payout API Key** — for sending payouts (used in the `X-API-KEY` header)
    - **Vendor ID** — your unique merchant identifier

    ### Step 2: Accept Your First Payment

    ```bash
    curl -X POST https://api-settlix.mint.0000.mx/api/v1/checkouts \
      -H "Content-Type: application/json" \
      -H "X-Api-Key: sk_your_key" \
      -d '{
        "reference": "order-12345",
        "amount": 1500,
        "paymentMethod": "easypaisa",
        "paymentType": "onetime",
        "successUrl": "https://yoursite.com/success",
        "returnUrl": "https://yoursite.com/cancel",
        "user": {
          "id": "cust_001",
          "email": "customer@example.com"
        }
      }'
    ```

    The response includes a `paymentUrl` — redirect your customer there to complete payment.

    ### Step 3: Handle the Result

    When the payment completes, we send a webhook to your configured URL:

    ```json
    {
      "event": "payment.completed",
      "data": {
        "checkoutId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "reference": "order-12345",
        "amount": 1500,
        "currency": "PKR",
        "status": "completed",
        "paymentMethod": "easypaisa",
        "completedAt": "2026-03-26T14:30:00.000Z"
      }
    }
    ```

    You can also poll the status:

    ```bash
    curl https://api-settlix.mint.0000.mx/api/v1/transactions/order-12345 \
      -H "X-Api-Key: sk_your_key"
    ```

    ### Step 4: Send a Payout

    ```bash
    curl -X POST https://api-settlix.mint.0000.mx/api/v1/payouts \
      -H "Content-Type: application/json" \
      -H "X-API-KEY: payo_your_key" \
      -H "X-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
      -d '{
        "merchantReference": "PAYOUT-001",
        "amount": 5000,
        "currency": "PKR",
        "destType": "BANK",
        "bankCode": "HBL",
        "accountNumber": "1234567890001",
        "accountTitle": "John Doe"
      }'
    ```

    ---

    ## Authentication

    | API | Header | Key Type |
    |-----|--------|----------|
    | Payments | `X-Api-Key: sk_your_key` | Payment API Key |
    | Payouts | `X-API-KEY: payo_your_key` | Payout API Key |
    | Payout mutations | `X-Idempotency-Key: uuid-v4` | Required for POST/PUT |

    ## Payment Methods

    - **Easypaisa** — Mobile wallet (Pakistan)
    - **JazzCash** — Mobile wallet (Pakistan)
    - **Card** — Visa/Mastercard

    ## Payout Destinations

    - **Bank Transfer** — 14 Pakistani banks (HBL, UBL, MCB, ABL, JSBL, BAHL, MEEZAN, ASKARI, BANKALHABIB, SONERI, FBL, BOP, NBP, SBP)
    - **Mobile Wallet** — EASYPAISA, JAZZCASH, SADAPAY, NAYAPAY

    ## Transaction Lifecycle

    1. **created** — Checkout session created
    2. **pending** — Customer redirected, awaiting payment
    3. **completed** — Payment successful
    4. **failed** — Payment failed or declined
    5. **expired** — Session timed out (15 min default)
    6. **refunded** — Payment refunded

    ## Payout Lifecycle

    1. **PENDING** — Payout queued for processing
    2. **PROCESSING** — Being processed by the bank/wallet
    3. **SUCCESS** — Funds delivered
    4. **FAILED** — Transfer failed (can reinitiate)
    5. **ON_HOLD** — Under manual review
    6. **IN_REVIEW** — Large amount, requires approval

    ## Webhooks

    Configure your webhook URL through the Settlix admin portal. We will send POST requests with:

    **Headers:**
    - `Content-Type: application/json`
    - `X-Webhook-Signature: hmac-sha256-signature`
    - `X-Webhook-Timestamp: unix-timestamp`

    **Payload:**
    ```json
    {
      "event": "payment.completed",
      "data": {
        "checkoutId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "reference": "order-12345",
        "amount": 1500,
        "currency": "PKR",
        "status": "completed",
        "paymentMethod": "easypaisa",
        "completedAt": "2026-03-26T14:30:00.000Z"
      }
    }
    ```

    **Events:** `payment.completed`, `payment.failed`, `payment.expired`, `payout.completed`, `payout.failed`

    **Retries:** 3 attempts with 5-second delays. Return HTTP 200 to acknowledge.

    **Verifying Signatures:**
    Compute an HMAC-SHA256 of the raw request body using your webhook secret and compare it to the `X-Webhook-Signature` header. Reject requests where the timestamp is older than 5 minutes to prevent replay attacks.

    ## Sandbox Testing

    ### Payment Test Numbers

    | Input | Result |
    |-------|--------|
    | Phone: `03030000000` | Success |
    | Phone: `03021111111` | Failed |
    | Card: `4242424242424242` | Success |
    | Card: `4000000000000002` | Declined |

    ### Payout Test Accounts

    | Account Suffix | Result |
    |----------------|--------|
    | `...0001` | SUCCESS |
    | `...0002` | RETRY then SUCCESS |
    | `...0003` | FAILED |
    | `...0004` | PENDING |
    | `...0005` | ON_HOLD |
    | Amount >= 100,000 | IN_REVIEW |

    ## Errors

    All errors follow a consistent format:

    ```json
    {
      "success": false,
      "error": "Human-readable message"
    }
    ```

    | Status | Meaning |
    |--------|---------|
    | 400 | Bad Request — invalid parameters |
    | 401 | Unauthorized — invalid or missing API key |
    | 404 | Not Found — resource does not exist |
    | 409 | Conflict — duplicate idempotency key |
    | 429 | Rate Limited — too many requests |
    | 500 | Server Error — contact support |

    ## Rate Limits

    | Window | Limit |
    |--------|-------|
    | Per second | 3 |
    | Per minute | 15 |
    | Per hour | 50 |
    | Per day | 100 |

    Exceeding limits returns 429 with a `Retry-After` header.

    ## Support

    Email: support@settlix.net
  contact:
    name: Settlix Support
    email: support@settlix.net

servers:
  - url: https://api-settlix.mint.0000.mx
    description: Settlix Sandbox

tags:
  - name: Accept Payments
    description: Create checkout sessions and retrieve transaction status.
  - name: Payouts
    description: Send payouts to bank accounts and mobile wallets.
  - name: Balance
    description: Query your account balance and transaction ledger.
  - name: Verification
    description: Verify bank accounts and mobile wallets before sending payouts.
  - name: Directory
    description: List supported banks and mobile wallet providers.
  - name: Health
    description: API health check.

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: |
        Payment API key issued by Settlix. Prefix: `sk_`.
        Used for checkout and transaction endpoints.
    PayoutApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
      description: |
        Payout API key issued by Settlix. Prefix: `payo_`.
        Used for payout, balance, directory, and verification endpoints.

  parameters:
    IdempotencyKey:
      name: X-Idempotency-Key
      in: header
      required: true
      description: |
        A unique UUID v4 for this request. Prevents duplicate operations if the
        same request is retried. The server returns the cached response for
        duplicate keys within a 24-hour window.
      schema:
        type: string
        format: uuid
        example: 550e8400-e29b-41d4-a716-446655440000

  schemas:
    # ── Request Bodies ────────────────────────────────────────────────
    CreateCheckoutRequest:
      type: object
      required:
        - reference
        - amount
        - paymentMethod
        - paymentType
        - successUrl
        - returnUrl
        - user
      properties:
        reference:
          type: string
          description: Your unique order or invoice reference. Must be unique per merchant.
          example: order-12345
        amount:
          type: number
          description: Payment amount in the smallest currency unit (e.g., PKR whole units).
          minimum: 1
          example: 1500
        paymentMethod:
          type: string
          enum: [easypaisa, jazzcash, card]
          description: The payment method the customer will use.
          example: easypaisa
        paymentType:
          type: string
          enum: [onetime]
          description: Payment type. Currently only `onetime` is supported.
          example: onetime
        successUrl:
          type: string
          format: uri
          description: URL to redirect the customer to after a successful payment.
          example: https://yoursite.com/success
        returnUrl:
          type: string
          format: uri
          description: URL to redirect the customer to if they cancel or go back.
          example: https://yoursite.com/cancel
        user:
          type: object
          required:
            - id
            - email
          properties:
            id:
              type: string
              description: Your internal customer identifier.
              example: cust_001
            email:
              type: string
              format: email
              description: Customer email address for receipts and notifications.
              example: customer@example.com

    CreatePayoutRequest:
      type: object
      required:
        - merchantReference
        - amount
        - currency
        - destType
        - accountNumber
        - accountTitle
      properties:
        merchantReference:
          type: string
          description: Your unique payout reference. Must be unique per merchant.
          example: PAYOUT-001
        amount:
          type: number
          description: Payout amount in PKR.
          minimum: 1
          example: 5000
        currency:
          type: string
          enum: [PKR]
          description: Currency code. Currently only PKR is supported.
          example: PKR
        destType:
          type: string
          enum: [BANK, WALLET]
          description: Destination type — bank account or mobile wallet.
          example: BANK
        bankCode:
          type: string
          description: |
            Required when `destType` is `BANK`. Use the `GET /directory` endpoint
            to retrieve valid codes.
          enum: [HBL, UBL, MCB, ABL, JSBL, BAHL, MEEZAN, ASKARI, BANKALHABIB, SONERI, FBL, BOP, NBP, SBP]
          example: HBL
        walletCode:
          type: string
          description: Required when `destType` is `WALLET`.
          enum: [EASYPAISA, JAZZCASH, SADAPAY, NAYAPAY]
          example: EASYPAISA
        accountNumber:
          type: string
          description: Destination bank account number or mobile wallet number.
          example: "1234567890001"
        accountTitle:
          type: string
          description: Account holder name as registered with the bank or wallet provider.
          example: John Doe

    VerifyAccountRequest:
      type: object
      required:
        - accountNumber
        - destType
      properties:
        accountNumber:
          type: string
          description: The bank account number or wallet phone number to verify.
          example: "1234567890001"
        destType:
          type: string
          enum: [BANK, WALLET]
          description: Whether the account is a bank account or mobile wallet.
          example: BANK
        bankCode:
          type: string
          description: Required when `destType` is `BANK`.
          example: HBL

    # ── Response Bodies ───────────────────────────────────────────────
    CheckoutResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            checkoutId:
              type: string
              format: uuid
              description: Unique checkout session identifier.
              example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
            paymentUrl:
              type: string
              format: uri
              description: Redirect your customer to this URL to complete payment.
              example: https://pay-settlix.mint.0000.mx/pay/a1b2c3d4-e5f6-7890-abcd-ef1234567890
            expiresAt:
              type: string
              format: date-time
              description: ISO 8601 timestamp when this checkout session expires (default 15 minutes).
              example: "2026-03-26T14:45:00.000Z"
            reference:
              type: string
              description: Your order reference, echoed back.
              example: order-12345
            amount:
              type: number
              example: 1500
            currency:
              type: string
              example: PKR
            status:
              type: string
              enum: [created, pending, completed, failed, expired, refunded]
              example: created

    CheckoutDetailResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            checkoutId:
              type: string
              format: uuid
              example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
            reference:
              type: string
              example: order-12345
            amount:
              type: number
              example: 1500
            currency:
              type: string
              example: PKR
            status:
              type: string
              enum: [created, pending, completed, failed, expired, refunded]
              example: completed
            paymentMethod:
              type: string
              enum: [easypaisa, jazzcash, card]
              example: easypaisa
            paymentUrl:
              type: string
              format: uri
              example: https://pay-settlix.mint.0000.mx/pay/a1b2c3d4-e5f6-7890-abcd-ef1234567890
            expiresAt:
              type: string
              format: date-time
              example: "2026-03-26T14:45:00.000Z"
            completedAt:
              type: string
              format: date-time
              nullable: true
              description: Timestamp when payment was completed, or null if not yet completed.
              example: "2026-03-26T14:32:00.000Z"
            createdAt:
              type: string
              format: date-time
              example: "2026-03-26T14:30:00.000Z"

    TransactionResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            checkoutId:
              type: string
              format: uuid
              example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
            reference:
              type: string
              example: order-12345
            amount:
              type: number
              example: 1500
            currency:
              type: string
              example: PKR
            status:
              type: string
              enum: [created, pending, completed, failed, expired, refunded]
              example: completed
            paymentMethod:
              type: string
              enum: [easypaisa, jazzcash, card]
              example: easypaisa
            completedAt:
              type: string
              format: date-time
              nullable: true
              example: "2026-03-26T14:32:00.000Z"
            createdAt:
              type: string
              format: date-time
              example: "2026-03-26T14:30:00.000Z"

    PayoutResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            id:
              type: string
              format: uuid
              example: f7e8d9c0-b1a2-3456-7890-abcdef123456
            merchantReference:
              type: string
              example: PAYOUT-001
            amount:
              type: number
              example: 5000
            currency:
              type: string
              example: PKR
            status:
              type: string
              enum: [PENDING, PROCESSING, SUCCESS, FAILED, ON_HOLD, IN_REVIEW]
              example: PENDING
            destType:
              type: string
              enum: [BANK, WALLET]
              example: BANK
            bankCode:
              type: string
              nullable: true
              example: HBL
            walletCode:
              type: string
              nullable: true
              example: null
            accountNumber:
              type: string
              description: Masked account number — only the last 4 digits are visible.
              example: "****0001"
            accountTitle:
              type: string
              example: John Doe
            createdAt:
              type: string
              format: date-time
              example: "2026-03-26T15:00:00.000Z"

    PayoutListResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: array
          items:
            $ref: '#/components/schemas/PayoutResponse/properties/data'
        pagination:
          type: object
          properties:
            page:
              type: integer
              example: 1
            limit:
              type: integer
              example: 20
            total:
              type: integer
              example: 42

    BalanceResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            balance:
              type: number
              description: Current available balance in PKR.
              example: 125000
            currency:
              type: string
              example: PKR

    BalanceHistoryResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
                example: e1d2c3b4-a5f6-7890-1234-567890abcdef
              type:
                type: string
                enum: [CREDIT, DEBIT]
                description: CREDIT for incoming payments, DEBIT for payouts and fees.
                example: CREDIT
              amount:
                type: number
                example: 1500
              balanceAfter:
                type: number
                example: 125000
              description:
                type: string
                example: "Payment received: order-12345"
              reference:
                type: string
                nullable: true
                example: order-12345
              createdAt:
                type: string
                format: date-time
                example: "2026-03-26T14:32:00.000Z"
        pagination:
          type: object
          properties:
            page:
              type: integer
              example: 1
            limit:
              type: integer
              example: 20
            total:
              type: integer
              example: 156

    DirectoryResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            banks:
              type: array
              items:
                type: object
                properties:
                  code:
                    type: string
                    example: HBL
                  name:
                    type: string
                    example: Habib Bank Limited
              example:
                - code: HBL
                  name: Habib Bank Limited
                - code: UBL
                  name: United Bank Limited
                - code: MCB
                  name: MCB Bank Limited
                - code: ABL
                  name: Allied Bank Limited
                - code: JSBL
                  name: JS Bank Limited
                - code: BAHL
                  name: Bank Al Habib Limited
                - code: MEEZAN
                  name: Meezan Bank Limited
                - code: ASKARI
                  name: Askari Bank Limited
                - code: BANKALHABIB
                  name: Bank Al Habib
                - code: SONERI
                  name: Soneri Bank Limited
                - code: FBL
                  name: Faysal Bank Limited
                - code: BOP
                  name: Bank of Punjab
                - code: NBP
                  name: National Bank of Pakistan
                - code: SBP
                  name: State Bank of Pakistan
            wallets:
              type: array
              items:
                type: object
                properties:
                  code:
                    type: string
                    example: EASYPAISA
                  name:
                    type: string
                    example: Easypaisa
              example:
                - code: EASYPAISA
                  name: Easypaisa
                - code: JAZZCASH
                  name: JazzCash
                - code: SADAPAY
                  name: SadaPay
                - code: NAYAPAY
                  name: NayaPay

    VerifyAccountResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            valid:
              type: boolean
              description: Whether the account exists and can receive funds.
              example: true
            accountTitle:
              type: string
              description: The registered account holder name, returned if the account is valid.
              example: John Doe
            bankCode:
              type: string
              nullable: true
              example: HBL

    HealthResponse:
      type: object
      properties:
        status:
          type: string
          example: ok
        timestamp:
          type: string
          format: date-time
          example: "2026-03-26T14:30:00.000Z"

    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: string
          description: A human-readable error message.
          example: Invalid API key

paths:
  # ═══════════════════════════════════════════════════════════════════
  # Accept Payments
  # ═══════════════════════════════════════════════════════════════════

  /api/v1/checkouts:
    post:
      operationId: createCheckout
      summary: Create a checkout session
      description: |
        Creates a new checkout session and returns a `paymentUrl`. Redirect your
        customer to this URL so they can complete payment using the specified
        payment method.

        The session expires after 15 minutes by default. You will receive a
        webhook when the payment is completed, fails, or expires.
      tags:
        - Accept Payments
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCheckoutRequest'
            example:
              reference: order-12345
              amount: 1500
              paymentMethod: easypaisa
              paymentType: onetime
              successUrl: https://yoursite.com/success
              returnUrl: https://yoursite.com/cancel
              user:
                id: cust_001
                email: customer@example.com
      responses:
        '201':
          description: Checkout session created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CheckoutResponse'
              example:
                success: true
                data:
                  checkoutId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  paymentUrl: https://pay-settlix.mint.0000.mx/pay/a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  expiresAt: "2026-03-26T14:45:00.000Z"
                  reference: order-12345
                  amount: 1500
                  currency: PKR
                  status: created
        '400':
          description: Invalid request parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: "\"reference\" is required"
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key
        '429':
          description: Rate limit exceeded.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Rate limit exceeded. Try again later.

  /api/v1/checkouts/{checkoutId}:
    get:
      operationId: getCheckout
      summary: Get checkout details
      description: |
        Retrieve the full details of a checkout session, including its current
        status. Use this to check whether a payment has been completed before
        your webhook arrives, or to display order status to your customer.
      tags:
        - Accept Payments
      security:
        - ApiKeyAuth: []
      parameters:
        - name: checkoutId
          in: path
          required: true
          description: The checkout session ID returned by `POST /checkouts`.
          schema:
            type: string
            format: uuid
            example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
      responses:
        '200':
          description: Checkout details retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CheckoutDetailResponse'
              example:
                success: true
                data:
                  checkoutId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  reference: order-12345
                  amount: 1500
                  currency: PKR
                  status: completed
                  paymentMethod: easypaisa
                  paymentUrl: https://pay-settlix.mint.0000.mx/pay/a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  expiresAt: "2026-03-26T14:45:00.000Z"
                  completedAt: "2026-03-26T14:32:00.000Z"
                  createdAt: "2026-03-26T14:30:00.000Z"
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key
        '404':
          description: Checkout session not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Checkout not found

  /api/v1/transactions/{reference}:
    get:
      operationId: getTransactionByReference
      summary: Get transaction by your order reference
      description: |
        Look up a transaction using your original order reference (the
        `reference` you passed when creating the checkout). This is useful when
        you want to check payment status using your own identifiers rather than
        the Settlix `checkoutId`.
      tags:
        - Accept Payments
      security:
        - ApiKeyAuth: []
      parameters:
        - name: reference
          in: path
          required: true
          description: The `reference` you provided in the `POST /checkouts` request.
          schema:
            type: string
            example: order-12345
      responses:
        '200':
          description: Transaction retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionResponse'
              example:
                success: true
                data:
                  checkoutId: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                  reference: order-12345
                  amount: 1500
                  currency: PKR
                  status: completed
                  paymentMethod: easypaisa
                  completedAt: "2026-03-26T14:32:00.000Z"
                  createdAt: "2026-03-26T14:30:00.000Z"
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key
        '404':
          description: No transaction found for this reference.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Transaction not found

  # ═══════════════════════════════════════════════════════════════════
  # Payouts
  # ═══════════════════════════════════════════════════════════════════

  /api/v1/payouts:
    post:
      operationId: createPayout
      summary: Create a payout
      description: |
        Send money to a bank account or mobile wallet. The payout is queued for
        processing and will transition through the payout lifecycle statuses.

        You must include an `X-Idempotency-Key` header. If the same key is sent
        again, the original response is returned without creating a duplicate
        payout.

        Use `GET /directory` to look up valid `bankCode` and `walletCode` values.
      tags:
        - Payouts
      security:
        - PayoutApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePayoutRequest'
            examples:
              bankPayout:
                summary: Bank transfer payout
                value:
                  merchantReference: PAYOUT-001
                  amount: 5000
                  currency: PKR
                  destType: BANK
                  bankCode: HBL
                  accountNumber: "1234567890001"
                  accountTitle: John Doe
              walletPayout:
                summary: Mobile wallet payout
                value:
                  merchantReference: PAYOUT-002
                  amount: 2000
                  currency: PKR
                  destType: WALLET
                  walletCode: EASYPAISA
                  accountNumber: "03001234567"
                  accountTitle: Jane Smith
      responses:
        '201':
          description: Payout created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayoutResponse'
              example:
                success: true
                data:
                  id: f7e8d9c0-b1a2-3456-7890-abcdef123456
                  merchantReference: PAYOUT-001
                  amount: 5000
                  currency: PKR
                  status: PENDING
                  destType: BANK
                  bankCode: HBL
                  walletCode: null
                  accountNumber: "****0001"
                  accountTitle: John Doe
                  createdAt: "2026-03-26T15:00:00.000Z"
        '400':
          description: Invalid request parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: "\"accountNumber\" is required"
        '401':
          description: Missing or invalid payout API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key
        '409':
          description: Duplicate idempotency key with different parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Idempotency key already used with different parameters
        '429':
          description: Rate limit exceeded.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Rate limit exceeded. Try again later.

    get:
      operationId: listPayouts
      summary: List your payouts
      description: |
        Retrieve a paginated list of your payouts. Results are ordered by
        creation date, most recent first. Use the query parameters to filter
        by status or paginate through results.
      tags:
        - Payouts
      security:
        - PayoutApiKeyAuth: []
      parameters:
        - name: page
          in: query
          required: false
          description: Page number (1-based).
          schema:
            type: integer
            minimum: 1
            default: 1
            example: 1
        - name: limit
          in: query
          required: false
          description: Number of results per page (max 100).
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
            example: 20
        - name: status
          in: query
          required: false
          description: Filter by payout status.
          schema:
            type: string
            enum: [PENDING, PROCESSING, SUCCESS, FAILED, ON_HOLD, IN_REVIEW]
            example: SUCCESS
      responses:
        '200':
          description: Payouts retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayoutListResponse'
              example:
                success: true
                data:
                  - id: f7e8d9c0-b1a2-3456-7890-abcdef123456
                    merchantReference: PAYOUT-001
                    amount: 5000
                    currency: PKR
                    status: SUCCESS
                    destType: BANK
                    bankCode: HBL
                    walletCode: null
                    accountNumber: "****0001"
                    accountTitle: John Doe
                    createdAt: "2026-03-26T15:00:00.000Z"
                  - id: a9b8c7d6-e5f4-3210-fedc-ba0987654321
                    merchantReference: PAYOUT-002
                    amount: 2000
                    currency: PKR
                    status: PENDING
                    destType: WALLET
                    bankCode: null
                    walletCode: EASYPAISA
                    accountNumber: "****4567"
                    accountTitle: Jane Smith
                    createdAt: "2026-03-26T14:50:00.000Z"
                pagination:
                  page: 1
                  limit: 20
                  total: 42
        '401':
          description: Missing or invalid payout API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key

  /api/v1/payouts/{id}:
    get:
      operationId: getPayout
      summary: Get payout details
      description: |
        Retrieve the full details of a single payout by its Settlix ID. Use this
        to check whether a payout has been delivered or to display its current
        status to your operations team.
      tags:
        - Payouts
      security:
        - PayoutApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: The payout ID returned by `POST /payouts`.
          schema:
            type: string
            format: uuid
            example: f7e8d9c0-b1a2-3456-7890-abcdef123456
      responses:
        '200':
          description: Payout details retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayoutResponse'
              example:
                success: true
                data:
                  id: f7e8d9c0-b1a2-3456-7890-abcdef123456
                  merchantReference: PAYOUT-001
                  amount: 5000
                  currency: PKR
                  status: SUCCESS
                  destType: BANK
                  bankCode: HBL
                  walletCode: null
                  accountNumber: "****0001"
                  accountTitle: John Doe
                  createdAt: "2026-03-26T15:00:00.000Z"
        '401':
          description: Missing or invalid payout API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key
        '404':
          description: Payout not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Payout not found

  /api/v1/payouts/{id}/reinitiate:
    post:
      operationId: reinitiatePayout
      summary: Retry a failed payout
      description: |
        Retry a payout that has a `FAILED` status. This creates a new processing
        attempt using the same payout details. Only payouts with status `FAILED`
        can be reinitiated.

        Requires an `X-Idempotency-Key` header to prevent duplicate retries.
      tags:
        - Payouts
      security:
        - PayoutApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: The ID of the failed payout to retry.
          schema:
            type: string
            format: uuid
            example: f7e8d9c0-b1a2-3456-7890-abcdef123456
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '200':
          description: Payout reinitiated successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayoutResponse'
              example:
                success: true
                data:
                  id: f7e8d9c0-b1a2-3456-7890-abcdef123456
                  merchantReference: PAYOUT-001
                  amount: 5000
                  currency: PKR
                  status: PENDING
                  destType: BANK
                  bankCode: HBL
                  walletCode: null
                  accountNumber: "****0001"
                  accountTitle: John Doe
                  createdAt: "2026-03-26T15:00:00.000Z"
        '400':
          description: Payout is not in a retriable state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Only FAILED payouts can be reinitiated
        '401':
          description: Missing or invalid payout API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key
        '404':
          description: Payout not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Payout not found
        '409':
          description: Duplicate idempotency key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Idempotency key already used with different parameters

  # ═══════════════════════════════════════════════════════════════════
  # Balance
  # ═══════════════════════════════════════════════════════════════════

  /api/v1/balance:
    get:
      operationId: getBalance
      summary: Get your current balance
      description: |
        Returns your current available balance. This reflects all settled
        incoming payments minus payouts and fees.
      tags:
        - Balance
      security:
        - PayoutApiKeyAuth: []
      responses:
        '200':
          description: Balance retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BalanceResponse'
              example:
                success: true
                data:
                  balance: 125000
                  currency: PKR
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key

  /api/v1/balance/history:
    get:
      operationId: getBalanceHistory
      summary: Get balance ledger history
      description: |
        Returns a paginated ledger of all balance changes, including credits
        (incoming payments) and debits (payouts, fees). Use this to reconcile
        your account or build transaction reports.
      tags:
        - Balance
      security:
        - PayoutApiKeyAuth: []
      parameters:
        - name: page
          in: query
          required: false
          description: Page number (1-based).
          schema:
            type: integer
            minimum: 1
            default: 1
            example: 1
        - name: limit
          in: query
          required: false
          description: Number of results per page (max 100).
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
            example: 20
      responses:
        '200':
          description: Balance history retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BalanceHistoryResponse'
              example:
                success: true
                data:
                  - id: e1d2c3b4-a5f6-7890-1234-567890abcdef
                    type: CREDIT
                    amount: 1500
                    balanceAfter: 125000
                    description: "Payment received: order-12345"
                    reference: order-12345
                    createdAt: "2026-03-26T14:32:00.000Z"
                  - id: d4c3b2a1-f6e5-0987-4321-fedcba098765
                    type: DEBIT
                    amount: 5000
                    balanceAfter: 120000
                    description: "Payout sent: PAYOUT-001"
                    reference: PAYOUT-001
                    createdAt: "2026-03-26T15:00:00.000Z"
                pagination:
                  page: 1
                  limit: 20
                  total: 156
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key

  # ═══════════════════════════════════════════════════════════════════
  # Directory
  # ═══════════════════════════════════════════════════════════════════

  /api/v1/directory:
    get:
      operationId: getDirectory
      summary: List supported banks and mobile wallets
      description: |
        Returns the full list of supported bank codes and mobile wallet codes.
        Use these codes in the `bankCode` or `walletCode` field when creating
        payouts or verifying accounts.
      tags:
        - Directory
      security:
        - PayoutApiKeyAuth: []
      responses:
        '200':
          description: Directory retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DirectoryResponse'
              example:
                success: true
                data:
                  banks:
                    - code: HBL
                      name: Habib Bank Limited
                    - code: UBL
                      name: United Bank Limited
                    - code: MCB
                      name: MCB Bank Limited
                    - code: ABL
                      name: Allied Bank Limited
                    - code: JSBL
                      name: JS Bank Limited
                    - code: BAHL
                      name: Bank Al Habib Limited
                    - code: MEEZAN
                      name: Meezan Bank Limited
                    - code: ASKARI
                      name: Askari Bank Limited
                    - code: BANKALHABIB
                      name: Bank Al Habib
                    - code: SONERI
                      name: Soneri Bank Limited
                    - code: FBL
                      name: Faysal Bank Limited
                    - code: BOP
                      name: Bank of Punjab
                    - code: NBP
                      name: National Bank of Pakistan
                    - code: SBP
                      name: State Bank of Pakistan
                  wallets:
                    - code: EASYPAISA
                      name: Easypaisa
                    - code: JAZZCASH
                      name: JazzCash
                    - code: SADAPAY
                      name: SadaPay
                    - code: NAYAPAY
                      name: NayaPay
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key

  # ═══════════════════════════════════════════════════════════════════
  # Verification
  # ═══════════════════════════════════════════════════════════════════

  /api/v1/verify-account:
    post:
      operationId: verifyAccount
      summary: Verify a bank account or wallet
      description: |
        Verify that a bank account or mobile wallet exists and can receive funds
        before sending a payout. Returns the registered account holder name so
        you can confirm it matches your records.

        Requires an `X-Idempotency-Key` header.
      tags:
        - Verification
      security:
        - PayoutApiKeyAuth: []
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyAccountRequest'
            examples:
              bankAccount:
                summary: Verify a bank account
                value:
                  accountNumber: "1234567890001"
                  destType: BANK
                  bankCode: HBL
              wallet:
                summary: Verify a mobile wallet
                value:
                  accountNumber: "03001234567"
                  destType: WALLET
      responses:
        '200':
          description: Account verification result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerifyAccountResponse'
              examples:
                valid:
                  summary: Account is valid
                  value:
                    success: true
                    data:
                      valid: true
                      accountTitle: John Doe
                      bankCode: HBL
                invalid:
                  summary: Account is invalid
                  value:
                    success: true
                    data:
                      valid: false
                      accountTitle: null
                      bankCode: HBL
        '400':
          description: Invalid request parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: "\"accountNumber\" is required"
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Invalid API key
        '409':
          description: Duplicate idempotency key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                error: Idempotency key already used with different parameters

  # ═══════════════════════════════════════════════════════════════════
  # Health
  # ═══════════════════════════════════════════════════════════════════

  /api/v1/health:
    get:
      operationId: healthCheck
      summary: API health check
      description: |
        Returns the current health status of the API. This endpoint does not
        require authentication and can be used for uptime monitoring.
      tags:
        - Health
      security: []
      responses:
        '200':
          description: API is healthy.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
              example:
                status: ok
                timestamp: "2026-03-26T14:30:00.000Z"
