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

# Build batch transaction

> Funds every order in the group with one ERC-4337 UserOperation instead of paying each deposit address. Every order must send the same source token — all the chain's native coin, or all the same ERC-20.

- fund the smart account: send the transaction to `to` with `data` and `value`, moving `tokenAmount` of the source token
- pass the signature to [Submit signed transaction](/api-reference/bundler-evm/submit-signed-transaction)
- large groups come back as several batches — handle every entry in `transactions`
- supported on Ethereum, Base and BNB Smart Chain. Other EVM chains are rejected with 400
- EVM only. For Solana use [Get batch transaction](/api-reference/bundler-sol/get-batch-transaction) instead

See the [multi-swap flow](https://docs.houdiniswap.com/developer-hub/swap-flows/multi-swap) for the full sequence.



## OpenAPI

````yaml https://api-partner.houdiniswap.com/v2/openapi.json post /exchanges/multi/{multiId}/tx/build
openapi: 3.0.0
info:
  title: Houdini Swap Partner API
  version: 2.1.2
  description: >-
    Quote and execute private, standard, and DEX swaps — one at a time or
    batched.
  license:
    name: ISC
  contact: {}
servers:
  - url: https://api-partner.houdiniswap.com/v2
security: []
tags:
  - name: Private and Standard Swaps
    description: >-
      CEX swaps in two modes, sharing the same endpoints — pick one with the
      `types` parameter.


      - `types=standard` — direct single-leg swap. Fastest, no privacy hop.

      - `types=private` — two legs through a privacy bridge, so deposit and
      payout are not linkable on-chain. Adds `anonymous`, `useXmr`,
      `rotatePayoutWallets` and the `inLeg*` / `outLeg*` filters.


      Flow: [Get tokens](/api-reference/private-and-standard-swaps/get-tokens)
      with `hasCex=true` → [Get
      quotes](/api-reference/private-and-standard-swaps/get-quotes) → [Create
      exchange](/api-reference/private-and-standard-swaps/create-exchange) →
      [track the
      order](/api-reference/private-and-standard-swaps/get-order-details).
      `markup` works in both modes.
  - name: Private Send
    description: >-
      Send a token to another wallet privately — same token in and out, with no
      on-chain link between the two addresses.


      - find eligible tokens with [Get
      tokens](/api-reference/private-send/get-tokens) and `hasSelfPrivate=true`

      - quote with Get private send quote, then create with Create private send
      order

      - you can also stay on the main endpoints with a private same-token
      `quoteId`


      See the [Private send](/docs/v2/private-send) guide.
  - name: Multi-Exchange
    description: >-
      Create and track a group of swaps sharing one `multiId`.


      - post the orders straight to Create multi exchange — there is no quote
      step and no `quoteId`

      - Get multi quotes is optional, for showing rates first

      - each order gets its own deposit address; poll [Get batch
      status](/api-reference/multi-exchange/get-batch-status) for every leg

      - CEX standard and private only — no DEX in a batch


      To fund the whole group in one transaction, see Bundler SOL or Bundler
      EVM. See the [multi-swap
      flow](https://docs.houdiniswap.com/developer-hub/swap-flows/multi-swap)
      for the full sequence.
  - name: Bundler SOL
    description: >-
      Fund a whole multi-exchange group with one Solana batch transfer.


      - one call — Get batch transaction returns the transaction to sign and
      broadcast

      - up to 10 deposits per batch; every order must send the same token

      - find batchable tokens with [Get
      tokens](/api-reference/multi-exchange/get-tokens) and `hasBundler=true`

      - nothing to submit back afterwards — retry and recovery are EVM-only


      See the [multi-swap
      flow](https://docs.houdiniswap.com/developer-hub/swap-flows/multi-swap)
      for the full sequence.
  - name: Bundler EVM
    description: >-
      Fund a whole multi-exchange group with one ERC-4337 UserOperation,
      submitted through the bundler.


      - Ethereum, Base and BNB Smart Chain only; other EVM chains are rejected

      - up to 20 legs per batch; every order must send the same source token

      - find batchable tokens with [Get
      tokens](/api-reference/multi-exchange/get-tokens) and `hasBundler=true`

      - build the UserOp, then submit the signed result

      - if a bundle fails: retry within 30 minutes, or recover stuck assets


      See the [multi-swap
      flow](https://docs.houdiniswap.com/developer-hub/swap-flows/multi-swap)
      for the full sequence.
  - name: On-chain DEX or Bridge
    description: >-
      On-chain swaps signed and funded from the user's own wallet.


      Flow: [Get tokens](/api-reference/on-chain-dex-or-bridge/get-tokens) with
      `hasDex=true` → [Get
      quotes](/api-reference/on-chain-dex-or-bridge/get-quotes) with `types=dex`
      → [Get token approval
      data](/api-reference/on-chain-dex-or-bridge/get-token-approval-data) →
      send it and poll [Check token
      allowance](/api-reference/on-chain-dex-or-bridge/check-token-allowance) →
      [Get next chain
      signature](/api-reference/on-chain-dex-or-bridge/get-next-chain-signature)
      → [Create exchange](/api-reference/on-chain-dex-or-bridge/create-exchange)
      → [Confirm DEX
      transaction](/api-reference/on-chain-dex-or-bridge/confirm-dex-transaction)
      → [track the
      order](/api-reference/on-chain-dex-or-bridge/get-order-details).


      - `slippage` applies to DEX only

      - `markup` is not supported
  - name: Reference Data
    description: >-
      Optional lookups: supported chains, liquidity providers, and per-pair
      min/max swap amounts. Responses are cached and change rarely — safe to
      fetch once and reuse. Token ids come from `/tokens`, listed in each swap
      section above.
  - name: Partner Account
    description: >-
      Your orders, profile, earned commissions, withdrawals, volume analytics,
      and the rate-limit budget attached to your API key. Every endpoint is
      scoped to the partner that owns the key making the request.
  - name: System
    description: >-
      Service health. [Get system
      health](/api-reference/system/get-system-health) is unauthenticated and
      exempt from x402 payment — use it for uptime monitoring.
paths:
  /exchanges/multi/{multiId}/tx/build:
    post:
      tags:
        - Bundler EVM
      summary: Build batch transaction
      description: >-
        Funds every order in the group with one ERC-4337 UserOperation instead
        of paying each deposit address. Every order must send the same source
        token — all the chain's native coin, or all the same ERC-20.


        - fund the smart account: send the transaction to `to` with `data` and
        `value`, moving `tokenAmount` of the source token

        - pass the signature to [Submit signed
        transaction](/api-reference/bundler-evm/submit-signed-transaction)

        - large groups come back as several batches — handle every entry in
        `transactions`

        - supported on Ethereum, Base and BNB Smart Chain. Other EVM chains are
        rejected with 400

        - EVM only. For Solana use [Get batch
        transaction](/api-reference/bundler-sol/get-batch-transaction) instead


        See the [multi-swap
        flow](https://docs.houdiniswap.com/developer-hub/swap-flows/multi-swap)
        for the full sequence.
      operationId: BuildMultiExchangeTx
      parameters:
        - description: The multi exchange group ID
          in: path
          name: multiId
          required: true
          schema:
            type: string
            maxLength: 64
          example: mx8Qa1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MultiExchangeTxBuildRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MultiExchangeTxResult'
              examples:
                Example 1:
                  value:
                    multiId: mx8Qa1
                    chain: evm
                    depositNeeded: '500012687'
                    saCurrentBalance: '0'
                    transactions:
                      - houdiniIds:
                          - hxK7mQp2
                          - hxK7mQp3
                        txData:
                          userOpHash: >-
                            0xa52e838c3667a152f26a3e039abe5bd0274261ef64dfa32d45c3a4604537852b
                          to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
                          data: >-
                            0xa9059cbb000000000000000000000000067423f2da169b79497f1ae57863a1d1ee7af772000000000000000000000000000000000000000000000000000000001dcdb5a6
                          value: '0'
                          chainId: 8453
                          tokenAmount: '500012687'
        '401':
          description: >-
            Credentials missing, malformed, or rejected — all return
            `INVALID_API_CREDENTIALS`. Sending only `partner-id` returns
            `PARTNER_ID_NOT_SUPPORTED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: >-
            Payment required — x402 protocol. The body is empty; what to pay is
            in the `payment-required` header. Not returned when you send an
            `Authorization` header.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402PaymentRequired'
          headers:
            payment-required:
              schema:
                type: string
              required: true
        '403':
          description: Access Denied
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Bundle already submitted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '429':
          description: Rate limit exceeded — back off and retry
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - apiKey: []
components:
  schemas:
    MultiExchangeTxBuildRequest:
      description: Request body for POST /exchanges/multi/{multiId}/tx/build
      properties:
        sender:
          type: string
          description: >-
            Wallet that will sign and fund the transaction(s). On EVM it also
            owns the smart account the batch runs through, so the same wallet
            must sign at [Submit signed
            transaction](/api-reference/bundler-evm/submit-signed-transaction).
          minLength: 1
        houdiniIds:
          items:
            type: string
          type: array
          description: >-
            Optional subset of orders to build for; defaults to all orders in
            the group
          maxItems: 50
      required:
        - sender
      type: object
      additionalProperties: false
    MultiExchangeTxResult:
      properties:
        multiId:
          type: string
          description: The group these transactions fund.
        chain:
          type: string
          description: Chain kind of the from token (e.g. "solana", "evm")
        transactions:
          items:
            $ref: '#/components/schemas/TxBatch'
          type: array
          description: >-
            One entry per batch. A group larger than the per-chain batch limit
            is split across several.
        depositNeeded:
          type: string
          description: >-
            Native coin the smart account still needs before you can submit, in
            wei. `"0"` means it is already funded.
        saCurrentBalance:
          type: string
          description: >-
            Native coin the smart account holds right now, in wei. The account
            is owned by the `sender` wallet, so this balance stays under the
            user's control.
      required:
        - multiId
        - chain
        - transactions
      type: object
      additionalProperties: false
    ErrorResponse:
      properties:
        message:
          type: string
        code:
          type: string
          description: >-
            Machine-readable reason for the failure. Branch on this, not on
            `message` — messages are free to change.


            The value depends on the HTTP status. The common ones:


            - `400` — `BAD_REQUEST`

            - `401` — `INVALID_API_CREDENTIALS`, `PARTNER_ID_NOT_SUPPORTED`

            - `403` — `ACCESS_DENIED`, `FIXED_RATE_NOT_ALLOWED`

            - `404` — `NOT_FOUND`, `TOKEN_NOT_FOUND`, `TOKEN_DISABLED`

            - `409` — `ALREADY_SUBMITTED`, `STATIC_DEPOSIT_IN_USE`

            - `422` — `VALIDATION_ERROR`, `AMOUNT_TOO_LOW`, `INVALID_SWAP`,
            `FIXED_RATE_QUOTE_EXPIRED`, and most other request problems

            - `429` — `RATE_LIMIT_EXCEEDED`

            - `5xx` — `INTERNAL_SERVER_ERROR`, `PROVIDER_EXCHANGE_FAILED`,
            `SERVICE_UNAVAILABLE`


            New codes are added over time, so treat this as an open set: match
            the ones you handle and fall back to the HTTP status for the rest.
        requestId:
          type: string
          description: >-
            Unique id for this request. Quote it when contacting support — it is
            how we find the failure in our logs.
      required:
        - message
        - code
      type: object
      additionalProperties: false
    X402PaymentRequired:
      description: >-
        Body of a `402 Payment required`. Empty — `{}` — for API clients; a
        request that looks like a browser gets an HTML paywall page instead.


        This is the x402 payment protocol, not the normal error format, so there
        is no `code` or `message` to branch on. What to pay is always in the
        `payment-required` response header, in both cases: base64-encoded JSON
        whose `accepts[]` entries each carry the `network`, the `asset` to pay
        in, the `amount`, and the `payTo` address, alongside `maxTimeoutSeconds`
        and the x402 `scheme`.


        Sending `Authorization` skips the payment flow, so a 402 only reaches
        callers paying per request. An `apiKey` query param also skips it but is
        not a credential — those requests fail with `401
        INVALID_API_CREDENTIALS`.
      properties: {}
      type: object
      additionalProperties: false
    ValidationError:
      properties:
        message:
          type: string
        code:
          type: string
          description: >-
            Machine-readable reason for the failure. Branch on this, not on
            `message` — messages are free to change.


            The value depends on the HTTP status. The common ones:


            - `400` — `BAD_REQUEST`

            - `401` — `INVALID_API_CREDENTIALS`, `PARTNER_ID_NOT_SUPPORTED`

            - `403` — `ACCESS_DENIED`, `FIXED_RATE_NOT_ALLOWED`

            - `404` — `NOT_FOUND`, `TOKEN_NOT_FOUND`, `TOKEN_DISABLED`

            - `409` — `ALREADY_SUBMITTED`, `STATIC_DEPOSIT_IN_USE`

            - `422` — `VALIDATION_ERROR`, `AMOUNT_TOO_LOW`, `INVALID_SWAP`,
            `FIXED_RATE_QUOTE_EXPIRED`, and most other request problems

            - `429` — `RATE_LIMIT_EXCEEDED`

            - `5xx` — `INTERNAL_SERVER_ERROR`, `PROVIDER_EXCHANGE_FAILED`,
            `SERVICE_UNAVAILABLE`


            New codes are added over time, so treat this as an open set: match
            the ones you handle and fall back to the HTTP status for the rest.
        requestId:
          type: string
          description: >-
            Unique id for this request. Quote it when contacting support — it is
            how we find the failure in our logs.
        fields:
          $ref: '#/components/schemas/FieldErrors'
      required:
        - message
        - code
        - fields
      type: object
      additionalProperties: false
    TxBatch:
      properties:
        houdiniIds:
          items:
            type: string
          type: array
          description: HoudiniIds of the orders included in this batch
        txData:
          anyOf:
            - $ref: '#/components/schemas/EvmBatchTxSlimData'
            - $ref: '#/components/schemas/BatchTxData'
          description: Network-specific transaction data ready to broadcast
      required:
        - houdiniIds
        - txData
      type: object
      additionalProperties: false
    FieldErrors:
      properties: {}
      type: object
      additionalProperties:
        properties:
          value: {}
          message:
            type: string
        required:
          - message
        type: object
    EvmBatchTxSlimData:
      description: The fields needed to sign and submit the batch.
      properties:
        userOpHash:
          type: string
          description: >-
            The digest the user's wallet must sign, as 32 bytes of hex. Sign it
            as a message — `signMessage({ message: { raw: userOpHash } })` in
            viem, `signMessage(getBytes(userOpHash))` in ethers — then post the
            signature to [Submit signed
            transaction](/api-reference/bundler-evm/submit-signed-transaction).
        to:
          type: string
          description: >-
            Where to send the funding transaction. It is **not** always the
            smart account:


            - ERC-20 source token — the token contract. The smart account is the
            recipient encoded inside `data`.

            - native source coin — the smart account itself.
        data:
          type: string
          description: >-
            Calldata for the funding transaction. An ERC-20 `transfer` moving
            the tokens to the smart account, or `0x` when the source token is
            the chain's native coin.


            The amount encoded here is the full balance the batch needs.
        value:
          type: string
          description: >-
            Native coin to send with the transaction, in wei. Covers gas plus
            the swap amount when the source token is the native coin, and is
            `"0"` for ERC-20 sources.
        chainId:
          type: number
          format: double
          description: EVM chain the batch runs on, e.g. `1` for Ethereum, `8453` for Base.
        tokenAmount:
          type: string
          description: >-
            How much of the source token still has to reach the smart account,
            in the token's smallest unit. Already funded balance is deducted.
            `"0"` when the source token is the chain's native coin.
      required:
        - userOpHash
        - to
        - data
        - value
        - chainId
        - tokenAmount
      type: object
      additionalProperties: false
    BatchTxData:
      anyOf:
        - $ref: '#/components/schemas/SolanaBatchTxData'
        - $ref: '#/components/schemas/EvmBatchTxData'
      description: Union — add new network types here as they are supported
    SolanaBatchTxData:
      properties:
        data:
          type: string
          description: Serialized transaction bytes (base64)
      required:
        - data
      type: object
      additionalProperties: false
    EvmBatchTxData:
      properties:
        userOp:
          $ref: '#/components/schemas/EvmUserOp'
        userOpHash:
          type: string
        chainId:
          type: number
          format: double
        entryPoint:
          type: string
        to:
          type: string
        smartAccountAddress:
          type: string
        gasEstimate:
          $ref: '#/components/schemas/EvmGasEstimate'
        data:
          type: string
        value:
          type: string
        tokenAmount:
          type: string
      required:
        - userOp
        - userOpHash
        - chainId
        - entryPoint
        - to
        - smartAccountAddress
        - gasEstimate
        - data
        - value
        - tokenAmount
      type: object
      additionalProperties: false
    EvmUserOp:
      description: >-
        EntryPoint v0.7 unpacked UserOp. User pays gas from Smart Account
        balance — no paymaster.
      properties:
        sender:
          type: string
        nonce:
          type: string
        factory:
          type: string
        factoryData:
          type: string
        callData:
          type: string
        callGasLimit:
          type: string
        verificationGasLimit:
          type: string
        preVerificationGas:
          type: string
        maxFeePerGas:
          type: string
        maxPriorityFeePerGas:
          type: string
        signature:
          type: string
        paymaster:
          type: string
        paymasterData:
          type: string
        paymasterVerificationGasLimit:
          type: string
        paymasterPostOpGasLimit:
          type: string
      required:
        - sender
        - nonce
        - callData
        - callGasLimit
        - verificationGasLimit
        - preVerificationGas
        - maxFeePerGas
        - maxPriorityFeePerGas
        - signature
      type: object
      additionalProperties: false
    EvmGasEstimate:
      properties:
        gasCostWei:
          type: string
        gasCostNative:
          type: string
        nativeSymbol:
          type: string
        totalTransferAmountWei:
          type: string
        requiredSmartAccountBalanceWei:
          type: string
        gasCostToken:
          type: string
        gasCostTokenDecimals:
          type: number
          format: double
        exchangeRate:
          type: string
        paymasterStub:
          type: boolean
      required:
        - gasCostWei
        - gasCostNative
        - nativeSymbol
        - totalTransferAmountWei
        - requiredSmartAccountBalanceWei
      type: object
      additionalProperties: false
  securitySchemes:
    apiKey:
      type: apiKey
      name: Authorization
      in: header
      description: >-
        Send `Authorization: <ApiKey>:<ApiSecret>` — joined by a colon, raw. No
        `Bearer` prefix, no base64.


        [Get your
        credentials](https://docs.houdiniswap.com/developer-hub/getting-started/authentication)

````

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