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

# Create a withdrawal

> Withdraws from a subaccount held by Matching with one signed WithdrawalModule action. The venue verifies the signature and that Matching records action.owner as the owner, simulates the withdrawal, and submits it through Matching.verifyAndMatch. Tokens are paid to action.owner. Every check fails closed.

Withdraws from a subaccount held by Matching — the kind every account created through the Numo app is. You sign
one `Action` for the `WithdrawalModule`; the venue verifies it and submits it through `Matching.verifyAndMatch`,
which lends the account to the module for the call. The module pays the action's `owner`, and the account stays in
Matching, so trading from it is not interrupted.

<Note>
  Signing costs no gas: the venue's executor submits the transaction. It is simulated first, so a withdrawal that
  would revert is refused before anything is sent.
</Note>

## Signing the action

Sign an [`Action`](/signing) against the same `Matching` domain as an order, with:

| Field          | Value                                                                                            |
| -------------- | ------------------------------------------------------------------------------------------------ |
| `subaccountId` | the subaccount, deposited in Matching with you as its recorded owner                             |
| `nonce`        | any unused `uint256`; nonces are per owner and per module, so order nonces never collide with it |
| `module`       | the WithdrawalModule: `0x0a10AE2f5D2482cE1e43bC309D430B8861C2b5aB` on Base                       |
| `data`         | `abi.encode(address asset, uint256 amount)`                                                      |
| `expiry`       | unix seconds, in the future and at most one hour ahead                                           |
| `owner`        | your address; the tokens are sent here                                                           |
| `signer`       | the same as `owner` (session keys are not supported yet)                                         |

`asset` is the wrapped asset your balance is held in, not the token it pays out:

| Balance | `asset`                                      | Paid out as                                       |
| ------- | -------------------------------------------- | ------------------------------------------------- |
| USDC    | `0x364058aFF6f36E01505fB2Cc870f8B6BD4835e84` | USDC `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
| cNGN    | `0x9D806fD040a719D27a8E5E77dc5aE0ED1e089493` | cNGN `0x46C85152bFe9f96829aA94755D9f915F9B10EF5F` |

`amount` is in the token's native decimals — 6 for both, so 1 USDC is `1000000`.

Send the action's seven fields as strings (numbers in base 10, `data` as hex) with the signature:

```json theme={null}
{
  "action": {
    "subaccount_id": "19",
    "nonce": "7328734720000000",
    "module": "0x0a10AE2f5D2482cE1e43bC309D430B8861C2b5aB",
    "data": "0x000000000000000000000000364058aff6f36e01505fb2cc870f8b6bd4835e8400000000000000000000000000000000000000000000000000000000001e82d7",
    "expiry": "1789400600",
    "owner": "0xYourAddress",
    "signer": "0xYourAddress"
  },
  "signature": "0x…"
}
```

## What is checked

In order, and every check fails closed — a signature or owner that cannot be read is refused, not waved through:

1. The request: module, subaccount (not 0), signer equals owner, expiry, `data` exactly two words, asset, amount
   above 0, signature shape. Refused with **400**.
2. At most one withdrawal in progress per owner, and five a minute. Refused with **429**.
3. The signature authorizes the action. Refused with **401**.
4. Matching holds the subaccount (**400**) and records `owner` as its owner (**403**).
5. The executor's simulation. A withdrawal that would revert is refused with **422**, and `revert` names the
   revert — for example `WERC_CannotBeNegative` for more than the account holds.

## The outcome

A **200** carries the transaction: `accepted`, `tx_hash`, `receipt_status` and `block_number`.
`receipt_status: "timeout"` means it was broadcast and had not confirmed when the venue answered — watch the hash
rather than treating it as failed.

A **502** means the venue could not confirm whether the withdrawal was submitted. Check your balance before signing
another: a second signed withdrawal is a second withdrawal. Resubmitting the *same* signed request is safe — its
nonce can only be spent once.


## OpenAPI

````yaml POST /v1/withdrawals
openapi: 3.1.0
info:
  title: Numo orderbook API
  description: >-
    REST endpoints exposed by Numo's markets-service and execution-service for
    dollar stablecoins. Real-time book, trades, and order streams are served
    over the WebSocket endpoint documented in the WebSocket streams reference.
  version: 1.0.0
servers:
  - url: https://api.numofx.com
    description: markets-service
  - url: https://executor.numofx.com
    description: execution-service
security: []
tags:
  - name: Markets service
  - name: Execution service
paths:
  /v1/withdrawals:
    post:
      tags:
        - Markets service
      summary: Create a withdrawal
      description: >-
        Withdraws from a subaccount held by Matching with one signed
        WithdrawalModule action. The venue verifies the signature and that
        Matching records action.owner as the owner, simulates the withdrawal,
        and submits it through Matching.verifyAndMatch. Tokens are paid to
        action.owner. Every check fails closed.
      operationId: createWithdrawal
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WithdrawalRequest'
      responses:
        '200':
          description: >-
            Submitted. receipt_status timeout means broadcast but not yet
            confirmed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalReceipt'
        '400':
          description: >-
            Malformed or off-policy request, or the subaccount is not deposited
            in Matching
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: The signature does not authorize the action
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Matching records another owner for the subaccount
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: >-
            The executor refused it: the simulation reverted, and revert names
            the revert
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalRejection'
        '429':
          description: >-
            A withdrawal for this owner is in progress, or more than five were
            requested in a minute
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: 'Outcome unknown: check the balance before signing another withdrawal'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: >-
            Withdrawals are not enabled, or the signature or owner could not be
            read
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    WithdrawalRequest:
      type: object
      required:
        - action
        - signature
      properties:
        action:
          type: object
          description: >-
            A Matching Action for the WithdrawalModule, signed with EIP-712
            against the Matching domain.
          required:
            - subaccount_id
            - nonce
            - module
            - data
            - expiry
            - owner
            - signer
          properties:
            subaccount_id:
              type: string
              description: Base-10 subaccount id, deposited in Matching.
            nonce:
              type: string
              description: Base-10 uint256, unused by this owner in the WithdrawalModule.
            module:
              type: string
              description: The WithdrawalModule address.
            data:
              type: string
              description: >-
                abi.encode(address asset, uint256 amount): the wrapped asset,
                and the amount in the token's native decimals.
            expiry:
              type: string
              description: Unix seconds; in the future and at most one hour ahead.
            owner:
              type: string
              description: >-
                The subaccount's owner as Matching records it. Tokens are paid
                here.
            signer:
              type: string
              description: Must equal owner.
        signature:
          type: string
          description: >-
            EIP-712 signature by signer: 65 bytes, or longer for an ERC-1271
            wallet.
    WithdrawalReceipt:
      type: object
      required:
        - accepted
        - tx_hash
      properties:
        accepted:
          type: boolean
          description: True once mined successfully.
        tx_hash:
          type: string
        receipt_status:
          type: string
          enum:
            - success
            - reverted
            - timeout
          description: 'timeout: broadcast, not yet confirmed.'
        block_number:
          type: string
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
    WithdrawalRejection:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        revert:
          type: string
          description: The revert the simulation hit, e.g. WERC_CannotBeNegative.

````