Skip to main content
Endpoints for building and submitting withdrawals from a perps DEX.
The example requests and responses on this page use Hyperliquid (dex: 'hyperliquid'). Request/response shapes (typed data structure, destination chains, and processing behavior) vary by DEX. Replace the dex value with any supported DEX from GET /dexes.
These endpoints are intended to be used via @lifi/perps-sdk. The typed data signing and submission flow is complex and best handled by the SDK.
Withdrawals are user-signed only. Agents cannot initiate withdrawals — this is a security feature. The withdrawal typed data requires the user’s wallet signature regardless of signing mode.

POST /createWithdrawal

Build a withdrawal payload for the user to sign.
POST /v1/perps/createWithdrawal

Flow

  1. Call this endpoint with the withdrawal details (destination address and amount)
  2. Backend builds the EIP-712 typed data for HyperliquidTransaction:Withdraw
  3. Sign the typedData in the returned action with the user’s wallet
  4. Submit the signature to POST /withdrawal

Request Body

{
  "dex": "hyperliquid",
  "address": "0x1234567890abcdef1234567890abcdef12345678",
  "withdrawal": {
    "destination": "0x1234567890abcdef1234567890abcdef12345678",
    "amount": "100.0"
  }
}
FieldTypeRequiredDescription
dexstringYesDEX identifier
addressstringYesUser’s wallet address (account owner)
withdrawalobjectYesWithdrawal details
withdrawal.destinationstringYesAddress to receive withdrawn funds
withdrawal.amountstringYesAmount to withdraw in USDC

Response 201

{
  "action": {
    "action": "Withdraw",
    "description": "Withdraw 100.0 USDC to 0x1234567890abcdef1234567890abcdef12345678",
    "typedData": {
      "domain": {
        "name": "HyperliquidSignTransaction",
        "version": "1",
        "chainId": 42161,
        "verifyingContract": "0x0000000000000000000000000000000000000000"
      },
      "types": {
        "EIP712Domain": [
          { "name": "name", "type": "string" },
          { "name": "version", "type": "string" },
          { "name": "chainId", "type": "uint256" },
          { "name": "verifyingContract", "type": "address" }
        ],
        "HyperliquidTransaction:Withdraw": [
          { "name": "hyperliquidChain", "type": "string" },
          { "name": "destination", "type": "string" },
          { "name": "amount", "type": "string" },
          { "name": "time", "type": "uint64" }
        ]
      },
      "primaryType": "HyperliquidTransaction:Withdraw",
      "message": {
        "hyperliquidChain": "Mainnet",
        "destination": "0x1234567890abcdef1234567890abcdef12345678",
        "amount": "100.0",
        "time": 1234567890
      }
    }
  }
}
SDK: createWithdrawal(), perps.buildWithdrawal()

POST /withdrawal

Submit a signed withdrawal.
POST /v1/perps/withdrawal

Request Body

{
  "dex": "hyperliquid",
  "address": "0x1234567890abcdef1234567890abcdef12345678",
  "action": {
    "action": "Withdraw",
    "typedData": { "...original typedData from createWithdrawal..." },
    "signature": "0xabcd1234..."
  }
}
FieldTypeRequiredDescription
dexstringYesDEX identifier
addressstringYesUser’s wallet address
actionobjectYesSigned withdrawal payload
action.actionstringYesAction type from /createWithdrawal
action.typedDataobjectYesOriginal typedData from /createWithdrawal
action.signaturestringYesUser’s signature of the typedData

Response 202

{
  "result": {
    "action": "Withdraw",
    "success": true
  }
}
FieldTypeDescription
result.actionstringAction type
result.successbooleanWhether the withdrawal was accepted
result.errorstringError message (if failed)
This endpoint returns 202 Accepted. Withdrawal processing is asynchronous. For Hyperliquid, the bridge transfer to Arbitrum typically takes 3–4 minutes. Poll GET /account to verify the balance change.

Response 400

Validation error (invalid parameters, invalid amount, or malformed request). SDK: submitWithdrawal(), perps.submitWithdrawal()