# Initiate a withdrawal from a tenant to an external destination address

Validates balance, reserves funds, dry-runs a CreateTransactionOrder intent on Custody, and returns an unsigned intent payload. The frontend signs the payload and submits it directly to Custody POST /v1/intents. The backend tracks confirmation asynchronously via a Temporal workflow keyed by the generated transactionOrderId.

Endpoint: POST /v1/domains/{domainId}/omnibus/{omnibusId}/tenants/{tenantId}/withdrawals

## Path parameters:

  - `domainId` (string, required)

  - `omnibusId` (string, required)

  - `tenantId` (string, required)

## Request fields (application/json):

  - `amount` (string, required)
    Positive integer in the ticker's smallest unit (e.g., wei for ETH, satoshis for BTC, drops for XRP). No leading zeros; zero is not allowed.

  - `tickerId` (string, required)
    Identifier of the ticker to withdraw

  - `ledgerId` (string, required)
    Identifier of the blockchain ledger to broadcast on

  - `destAddress` (string, required)
    External destination address. Must be outside this omnibus.

## Response 201 fields (application/json):

  - `withdrawal` (object, required)

  - `withdrawal.operationId` (string, required)
    Operation ID for the withdrawal

  - `withdrawal.transferId` (string, required)
    Transfer ID for the on-chain movement

  - `withdrawal.status` (string, required)
    Enum: "PENDING", "IN_PROGRESS", "COMPLETED", "FAILED", "CANCELLED"

  - `withdrawal.amount` (string, required)
    Positive integer in the ticker's smallest unit

  - `withdrawal.tickerId` (string, required)

  - `withdrawal.ledgerId` (string, required)

  - `withdrawal.destAddress` (string, required)
    External destination address

  - `withdrawal.estimatedFee` (string)
    Estimated on-chain fee captured at dry-run time

  - `withdrawal.custodyTransactionOrderId` (string)
    Custody TransactionOrder ID generated for this withdrawal

  - `withdrawal.createdAt` (string, required)
    Timestamp of the underlying operation row creation

  - `withdrawal.updatedAt` (string, required)
    Timestamp of the last status change on the underlying operation

  - `unsignedIntent` (object, required)
    Complete Propose object ready to be signed and submitted to Custody via POST /v1/intents. The frontend signs this object and sends it as the "request" field in ProposeIntentBody.

  - `unsignedIntent.type` (string, required)
    Intent type, always "Propose"
    Enum: "Propose"

  - `unsignedIntent.id` (string, required)
    Unique identifier for the intent

  - `unsignedIntent.author` (object, required)
    The user proposing the intent

  - `unsignedIntent.author.domainId` (string, required)

  - `unsignedIntent.author.id` (string, required)

  - `unsignedIntent.expiryAt` (string, required)
    Expiry time for the intent

  - `unsignedIntent.targetDomainId` (string, required)
    Domain where the intent will be executed

  - `unsignedIntent.payload` (any, required)
    The intent payload

  - `unsignedIntent.description` (string)
    Description of the intent

  - `unsignedIntent.customProperties` (object, required)
    Intent-level custom properties


