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

# Create a v2 transfer

> Creates a v2 payout transfer and returns a hardcoded deposit address for the requested `source_token`/`source_network` combination. Unlike v1, the deposit address is fixed — no provider API call is made at initiation time.

**v2 differences from v1:**
- **USDC only** — USDT transfers must use `POST /api/payouts/transfer`.
- **No expiry** — there is no time window to send funds. The transfer remains open until you send USDC and call `POST /api/payouts/transfer/v2/confirm-transfer`.
- **Two-phase confirmation** — after sending USDC on-chain, you must call `POST /api/payouts/transfer/v2/confirm-transfer` with the `transfer_id` and `tx_hash` to trigger the payout pipeline. The platform matches the deposit to your transfer using the provided transaction hash.

**Wallet compliance screening (conditional, per-account):** when compliance screening is enabled for your account (the default), `wallet_address` is **required**, must be an **EVM** address (0x + 40 hex chars), and is screened before any other processing. A wallet that fails screening is rejected with `403`. When screening is disabled for your account, `wallet_address` stays KYC-conditional (see below) and Solana addresses are accepted.

**KYC wallet verification (conditional, per-account):** if your account requires KYC verification, `wallet_address` is required and must be a KYC-verified wallet or the request is rejected with `403` (verify at kyc.madhousewallet.com); if KYC is not enabled for your account, `wallet_address` may be omitted (unless compliance screening requires it).

**Workflow:**
1. `GET /api/payouts/quote` → save `quoteId`.
2. `POST /api/payouts/transfer/v2` with `quote_id`, `amount`, `recipientId`, `source_network` (and `wallet_address` — required if compliance screening or KYC is enabled for your account) → receive `deposit_address` and `transfer_id`.
3. Send exactly `amount` USDC to `deposit_address` on `source_network`.
4. Call `POST /api/payouts/transfer/v2/confirm-transfer` with `transfer_id` and the on-chain `tx_hash`.
5. The platform detects the deposit and automatically initiates the fiat payout — email confirmation sent.

**Supported networks for v2 (USDC only):** `base`, `solana`, `polygon`, `arbitrum`, `avalanche`, `ethereum`.

**Rate limit:** 20 requests/minute.



## OpenAPI

````yaml /openapi.json post /api/payouts/transfer/v2
openapi: 3.0.3
info:
  title: MW Payouts API
  version: 1.0.0
  description: >-
    The MW Payouts API lets you programmatically retrieve exchange-rate quotes,
    calculate platform fees, and submit USDC-to-fiat payout transfers on behalf
    of your account.


    All requests must be authenticated with an API key obtained from the
    **Developers** section of the dashboard. API keys are for **server-side use
    only** — never embed them in client-side code.
  contact:
    name: MW Support
    email: support@madhousewallet.com
servers:
  - url: https://business.madhousewallet.com
    description: Production
security:
  - BearerAuth: []
tags:
  - name: Payouts
    description: USDC-to-fiat payout operations
  - name: Recipients
    description: Payout recipient management
paths:
  /api/payouts/transfer/v2:
    post:
      tags:
        - Payouts
      summary: Create a v2 transfer
      description: >-
        Creates a v2 payout transfer and returns a hardcoded deposit address for
        the requested `source_token`/`source_network` combination. Unlike v1,
        the deposit address is fixed — no provider API call is made at
        initiation time.


        **v2 differences from v1:**

        - **USDC only** — USDT transfers must use `POST /api/payouts/transfer`.

        - **No expiry** — there is no time window to send funds. The transfer
        remains open until you send USDC and call `POST
        /api/payouts/transfer/v2/confirm-transfer`.

        - **Two-phase confirmation** — after sending USDC on-chain, you must
        call `POST /api/payouts/transfer/v2/confirm-transfer` with the
        `transfer_id` and `tx_hash` to trigger the payout pipeline. The platform
        matches the deposit to your transfer using the provided transaction
        hash.


        **Wallet compliance screening (conditional, per-account):** when
        compliance screening is enabled for your account (the default),
        `wallet_address` is **required**, must be an **EVM** address (0x + 40
        hex chars), and is screened before any other processing. A wallet that
        fails screening is rejected with `403`. When screening is disabled for
        your account, `wallet_address` stays KYC-conditional (see below) and
        Solana addresses are accepted.


        **KYC wallet verification (conditional, per-account):** if your account
        requires KYC verification, `wallet_address` is required and must be a
        KYC-verified wallet or the request is rejected with `403` (verify at
        kyc.madhousewallet.com); if KYC is not enabled for your account,
        `wallet_address` may be omitted (unless compliance screening requires
        it).


        **Workflow:**

        1. `GET /api/payouts/quote` → save `quoteId`.

        2. `POST /api/payouts/transfer/v2` with `quote_id`, `amount`,
        `recipientId`, `source_network` (and `wallet_address` — required if
        compliance screening or KYC is enabled for your account) → receive
        `deposit_address` and `transfer_id`.

        3. Send exactly `amount` USDC to `deposit_address` on `source_network`.

        4. Call `POST /api/payouts/transfer/v2/confirm-transfer` with
        `transfer_id` and the on-chain `tx_hash`.

        5. The platform detects the deposit and automatically initiates the fiat
        payout — email confirmation sent.


        **Supported networks for v2 (USDC only):** `base`, `solana`, `polygon`,
        `arbitrum`, `avalanche`, `ethereum`.


        **Rate limit:** 20 requests/minute.
      operationId: createTransferV2
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - quote_id
                - amount
                - recipientId
                - source_token
                - source_network
                - customer_uuid
              properties:
                quote_id:
                  type: string
                  format: uuid
                  description: >-
                    UUID returned by `GET /api/payouts/quote`. Must be used
                    within 5 minutes.
                  example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
                wallet_address:
                  type: string
                  description: >-
                    The address on `source_network` that will send USDC to the
                    deposit address. Conditionally required: required if
                    compliance screening or KYC verification is enabled for your
                    account; may be omitted otherwise (stored and returned as an
                    empty string). When compliance screening is enabled (the
                    default), it must be an EVM address (0x + 40 hex chars) and
                    is screened before processing — Solana addresses are
                    rejected. When screening is disabled, both EVM (0x + 40 hex
                    chars) and Solana (base58, 32–44 chars) addresses are
                    accepted; if KYC is enabled it must be a KYC-verified
                    wallet.
                  example: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B'
                amount:
                  type: number
                  description: >-
                    USD amount to transfer (max 2 decimal places, must match the
                    quoted amount ±$0.01).
                  example: 500
                recipientId:
                  type: integer
                  description: >-
                    Recipient account ID from `GET /api/payouts/recipients` or
                    `POST /api/payouts/recipients`.
                  example: 12345678
                source_token:
                  type: string
                  enum:
                    - usdc
                  description: >-
                    Source token. Only `usdc` is accepted on v2. Use `POST
                    /api/payouts/transfer` for USDT.
                  example: usdc
                source_network:
                  type: string
                  enum:
                    - base
                    - solana
                    - polygon
                    - arbitrum
                    - avalanche
                    - ethereum
                  description: Network on which you will send USDC to the deposit address.
                  example: base
                customer_uuid:
                  type: string
                  format: uuid
                  description: >-
                    Your own UUID for this transfer — stored for audit and
                    duplicate prevention. A duplicate UUID is rejected with 409.
                  example: 550e8400-e29b-41d4-a716-446655440000
                keep_recipient:
                  type: boolean
                  description: >-
                    When `true`, the recipient is not automatically deleted
                    after the transfer reaches a terminal state. Defaults to
                    `false`.
                  example: false
                customer_email:
                  type: string
                  format: email
                  description: >-
                    Email address to receive payout status notifications (sent
                    and failed). If omitted, notifications are sent to the
                    authenticated account's email address.
                  example: customer@example.com
            example:
              quote_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
              wallet_address: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B'
              amount: 500
              recipientId: 12345678
              source_token: usdc
              source_network: base
              customer_uuid: 550e8400-e29b-41d4-a716-446655440000
              customer_email: customer@example.com
      responses:
        '200':
          description: Transfer created — deposit address returned
          content:
            application/json:
              schema:
                type: object
                required:
                  - transfer_id
                  - deposit_address
                  - source_token
                  - source_network
                  - amount
                  - currency
                  - wallet_address
                  - instructions
                properties:
                  transfer_id:
                    type: string
                    description: >-
                      Unique transfer reference. Use this ID with `POST
                      /api/payouts/transfer/v2/confirm-transfer`.
                    example: 507f1f77bcf86cd799439011
                  deposit_address:
                    type: string
                    description: >-
                      The address to send USDC to on `source_network`. This is a
                      fixed offloader wallet address.
                    example: '0xBC91bCF38e3c0DE1E3fD0cF50Be7c0e52D55D00e'
                  source_token:
                    type: string
                    description: Token to send (always `usdc` on v2).
                    example: usdc
                  source_network:
                    type: string
                    description: Network on which to send USDC.
                    example: base
                  amount:
                    type: number
                    description: USD amount to send.
                    example: 500
                  currency:
                    type: string
                    description: Target payout currency.
                    example: EUR
                  wallet_address:
                    type: string
                    description: >-
                      Your sender address as supplied in the request. Empty
                      string when omitted (KYC not enabled for your account).
                    example: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B'
                  instructions:
                    type: object
                    description: Human-readable instructions for completing the transfer.
                    properties:
                      send_amount:
                        type: number
                        example: 500
                      send_token:
                        type: string
                        example: USDC
                      send_network:
                        type: string
                        example: base
                      deposit_address:
                        type: string
                        example: '0xBC91bCF38e3c0DE1E3fD0cF50Be7c0e52D55D00e'
                      note:
                        type: string
                        description: Next step reminder.
                        example: >-
                          Send exactly 500 USDC on base to deposit_address, then
                          call POST /api/payouts/transfer/v2/confirm-transfer
                          with transfer_id and tx_hash to trigger the payout
                          pipeline.
              example:
                transfer_id: 507f1f77bcf86cd799439011
                deposit_address: '0xBC91bCF38e3c0DE1E3fD0cF50Be7c0e52D55D00e'
                source_token: usdc
                source_network: base
                amount: 500
                currency: EUR
                wallet_address: '0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B'
                instructions:
                  send_amount: 500
                  send_token: USDC
                  send_network: base
                  deposit_address: '0xBC91bCF38e3c0DE1E3fD0cF50Be7c0e52D55D00e'
                  note: >-
                    Send exactly 500 USDC on base to deposit_address, then call
                    POST /api/payouts/transfer/v2/confirm-transfer with
                    transfer_id and tx_hash to trigger the payout pipeline.
        '400':
          description: >-
            Validation error — invalid amount, missing/expired quote, mismatched
            amount, USDT not allowed on v2, unsupported network, or
            `wallet_address` missing/non-EVM when compliance screening is
            enabled for your account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Recipient not owned by your account, no deployed wallet,
            `wallet_address` failed compliance screening, or `wallet_address` is
            not KYC-verified — verify it at kyc.madhousewallet.com
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            Duplicate `customer_uuid` — this UUID has already been used for a
            previous transfer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded (20 requests/minute per key)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >-
            Compliance screening or wallet verification service unavailable, or
            screening not configured — retry after a short delay.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message
      required:
        - error
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Pass your API key as a Bearer token: `Authorization: Bearer
        mw_live_<keyId>_<secret>`

````