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

# Create Transfer

> Move funds between the deposit wallet, a venue trading wallet, or an external address - one verb for every direction.

`POST /transfers` is the single endpoint for every fund-movement direction. `<venue>` is one of `polymarket`, `predict`, `opinion`, `limitless`:

| `from`    | `to`       | Use case                                    |
| --------- | ---------- | ------------------------------------------- |
| `deposit` | `<venue>`  | Fund a venue from the deposit wallet        |
| `<venue>` | `deposit`  | Drain a venue back to the deposit wallet    |
| `deposit` | `external` | Withdraw USDC to a partner-supplied address |

Rejected routes return `400` synchronously with the unified error envelope (`{ error, message, requestId }` — see [Error Handling](/execution/overview#error-handling)). The `error` field carries the code below:

| Route                          | `error`                   | Why                                                                                                                                                                                                                              |
| ------------------------------ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<venue>` → `<venue>`          | `unsupported_route_v1`    | Accepted by the schema, rejected at execution in v1. Drain to deposit first, then fund the other venue.                                                                                                                          |
| `<venue>` → `external`         | `withdraw_via_deposit`    | Drain to deposit first, then withdraw from there.                                                                                                                                                                                |
| `external` → anywhere via POST | `inbound_requires_quote`  | Inbound deposits use [Quote Transfer](/trading-api/funds/quote-transfer); the partner submits the bridge tx themselves.                                                                                                          |
| `from === to`                  | `same_endpoint`           | Source and destination must differ.                                                                                                                                                                                              |
| `hyperliquid` on either side   | `hyperliquid_uses_across` | Hyperliquid is funded via [Across](https://across.to) and withdrawn via the per-venue [`POST /withdraw`](/trading-api/accounts/withdraw) - see [Funding & Withdrawals](/trading-api/guides/funding-and-withdrawals#hyperliquid). |
| `amount < $1 USD`              | `amount_below_minimum`    | Bridge fees dominate below \$1 of notional. Use a larger amount.                                                                                                                                                                 |

## Status semantics

`status` is a 3-state partner-facing enum:

| Value       | Meaning                                                               |
| ----------- | --------------------------------------------------------------------- |
| `pending`   | Still settling. Includes routes in automated recovery - keep polling. |
| `completed` | Funds landed at the destination. Terminal.                            |
| `failed`    | Did not deliver. Terminal. See `error` / `errorCode`.                 |

`substatus` adds context:

| Value                | Meaning                                                         |
| -------------------- | --------------------------------------------------------------- |
| `recoveryInProgress` | A transient on-chain step is being retried. Funds are not lost. |
| `escalated`          | Automated recovery exhausted - contact support.                 |
| `legacyPartial`      | Historical pre-recovery row; ignore for new integrations.       |

<Note>
  Same-chain routes (e.g. `deposit ↔ limitless`) settle synchronously and return `status: "completed"` on the POST response. Cross-token routes (e.g. `deposit → predict`) involve a swap and may return `pending` - poll [Get Transfer](/trading-api/funds/get-transfer) until terminal.
</Note>

## Idempotency

Pass `clientReferenceId` to make retries safe. The first request creates the transfer; a retry with the same `clientReferenceId` returns the existing record rather than starting a duplicate. Use a fresh value per logical operation - reusing one across different routes returns the first transfer regardless of the new body.


## OpenAPI

````yaml POST /api/accounts/{accountId}/transfers
openapi: 3.1.0
info:
  title: Predexon Trading API
  description: Unified trading API for prediction markets
  version: 1.0.0
servers:
  - url: https://trade.predexon.com
security:
  - ApiKeyAuth: []
paths:
  /api/accounts/{accountId}/transfers:
    post:
      tags:
        - Trading (Transfers)
      summary: Create Transfer
      description: >-
        Move funds between the deposit wallet, a venue trading wallet, or an
        external address. One verb for every fund-movement direction; see the
        [Transfers guide](/trading-api/guides/funding-and-withdrawals) for the
        route matrix.
      operationId: create_transfer
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTransferRequest'
      responses:
        '201':
          description: >-
            Transfer created. `status` is one of: `pending` (cross-token routes
            that may take time — poll GET /transfers/{transferId}), `completed`
            (terminal success — funds delivered), or **`failed`** (terminal
            failure — on-chain revert or recovery exhausted; read
            `transfer.error` + `transfer.errorCode` for detail). Same-token
            routes typically return `completed` synchronously.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Transfer'
        '400':
          description: >-
            Bad request — the `error` field carries the specific code.
            Route-rejection codes: `same_endpoint` (from === to),
            `unsupported_route_v1` (venue→venue not supported — drain to deposit
            first), `withdraw_via_deposit` (venue→external not supported — drain
            to deposit first), `inbound_requires_quote` (external→* uses POST
            /transfers/quote), `hyperliquid_uses_across` (Hyperliquid uses
            dedicated funding endpoints). Validation codes:
            `amount_below_minimum` (transfers must be ≥ $1 USD — bridge fees
            dominate below that), `invalid_amount`, `slippage_below_floor`,
            `slippage_too_high`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Account is not owned by this API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: Account not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
components:
  schemas:
    CreateTransferRequest:
      type: object
      required:
        - from
        - to
        - amount
      description: >-
        Move funds between the account's deposit wallet, a venue trading wallet,
        or an external address. Supported routes today: `deposit ↔ <venue>`
        (fund / drain a venue), `deposit → external` (withdraw). See the
        [Transfers guide](/trading-api/guides/funding-and-withdrawals) for the
        full route matrix.
      properties:
        from:
          type: string
          enum:
            - deposit
            - polymarket
            - predict
            - opinion
            - limitless
          description: >-
            Source wallet. `deposit` is the account's Base USDC deposit wallet;
            venue values are the account's venue trading wallets.
        to:
          type: string
          enum:
            - deposit
            - polymarket
            - predict
            - opinion
            - limitless
            - external
          description: >-
            Destination wallet. `external` is a partner-supplied address — see
            `destination`.
        amount:
          type: string
          description: >-
            Amount in the source token's natural unit (USDC for `deposit`
            source; USDT/pUSD for venue sources). Decimal string, e.g.
            `"100.00"`.
        destination:
          type: object
          description: >-
            Required when `to === "external"`. Recipient address + delivery
            chain/token.
          properties:
            address:
              type: string
            chain:
              type: string
              enum:
                - ethereum
                - polygon
                - base
                - bsc
                - arbitrum
                - optimism
            token:
              type: string
              description: >-
                Token symbol — `USDC`, `USDT`, or chain-specific (e.g. `USDC.e`
                on Polygon).
        clientReferenceId:
          type: string
          description: >-
            Partner-supplied idempotency key. Retries with the same key return
            the existing transfer rather than creating a duplicate.
    Transfer:
      type: object
      description: >-
        A single fund-movement operation. Same envelope returned by `POST
        /transfers`, `GET /transfers`, and `GET /transfers/{transferId}`.
        `status` is the partner-facing 3-state enum; `substatus` carries
        additional context where useful.
      properties:
        transferId:
          type: string
          description: >-
            Stable identifier (`tfr-...`). Use for `GET
            /transfers/{transferId}`.
        accountId:
          type: string
        from:
          type: object
          description: Source side of the transfer.
          properties:
            wallet:
              type: string
              description: '`deposit`, a venue name, or `external`.'
            chain:
              type: integer
            token:
              type: string
            address:
              type: string
        to:
          type: object
          description: Destination side of the transfer.
          properties:
            wallet:
              type: string
            chain:
              type: integer
            token:
              type: string
            address:
              type: string
        amount:
          type: string
          description: Source-side amount (echo of the request).
        amountReceived:
          type: string
          nullable: true
          description: >-
            Destination-side amount actually delivered. Populated once the
            transfer settles.
        status:
          type: string
          enum:
            - pending
            - completed
            - failed
          description: >-
            Partner-facing 3-state status. `pending` includes routes still in
            active recovery; `failed` includes routes that exhausted recovery
            (see `substatus`).
        substatus:
          type: string
          enum:
            - recoveryInProgress
            - escalated
            - legacyPartial
          nullable: true
          description: >-
            Optional context. `recoveryInProgress` — a transient on-chain step
            is being retried (poll until terminal). `escalated` — automated
            recovery exhausted; contact support. `legacyPartial` — historical
            pre-recovery-worker rows only.
        txHashes:
          type: object
          description: >-
            On-chain transaction hashes for each step that fired. Most routes
            use only `source`/`dest` (sometimes `approve`); venue-specific
            routes add `wrap`/`unwrap` (Polymarket), `safeExtract`/`safeDeposit`
            (Opinion), or `swap` (cross-token routes).
          properties:
            source:
              type: string
            dest:
              type: string
            approve:
              type: string
            unwrap:
              type: string
            wrap:
              type: string
            safeExtract:
              type: string
            safeDeposit:
              type: string
            swap:
              type: string
        explorerLink:
          type: string
          nullable: true
          description: >-
            Bridge-explorer URL for cross-chain transfers. `null` for same-chain
            transfers.
        clientReferenceId:
          type: string
          nullable: true
        createdAt:
          type: string
        completedAt:
          type: string
          nullable: true
        error:
          type: string
          nullable: true
          description: Human-readable failure message. Present iff `status === "failed"`.
        errorCode:
          type: string
          nullable: true
          description: Machine-readable failure code. Present iff `status === "failed"`.
    ApiError:
      type: object
      description: >-
        Unified error envelope returned by every endpoint on any 4xx or 5xx
        response. The `error` field is a stable snake_case code partners can
        branch on; `message` is the human-readable explanation (free-form, may
        change); `requestId` is the request correlation id (also returned in the
        `x-request-id` response header) — quote it when contacting support.
      required:
        - error
        - message
        - requestId
      properties:
        error:
          type: string
          description: >-
            Stable machine-readable code. See [Error
            codes](/trading-api/error-codes) for the full list. Snake_case,
            never renamed once shipped.
          example: insufficient_balance
        message:
          type: string
          description: >-
            Human-readable explanation. Free-form text that may include
            specifics (amounts, IDs, hints); do not parse — branch on `error`
            instead.
          example: 'Insufficient balance: need 50.000000, have 12.500000'
        requestId:
          type: string
          format: uuid
          description: >-
            Request correlation id. Quote this when filing a support ticket.
            Also returned in the `x-request-id` response header on every
            response (success or failure).
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````