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
- Call this endpoint with the withdrawal details (destination address and amount)
- Backend builds the EIP-712 typed data for
HyperliquidTransaction:Withdraw
- Sign the
typedData in the returned action with the user’s wallet
- Submit the signature to
POST /withdrawal
Request Body
{
"dex": "hyperliquid",
"address": "0x1234567890abcdef1234567890abcdef12345678",
"withdrawal": {
"destination": "0x1234567890abcdef1234567890abcdef12345678",
"amount": "100.0"
}
}
| Field | Type | Required | Description |
|---|
dex | string | Yes | DEX identifier |
address | string | Yes | User’s wallet address (account owner) |
withdrawal | object | Yes | Withdrawal details |
withdrawal.destination | string | Yes | Address to receive withdrawn funds |
withdrawal.amount | string | Yes | Amount 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..."
}
}
| Field | Type | Required | Description |
|---|
dex | string | Yes | DEX identifier |
address | string | Yes | User’s wallet address |
action | object | Yes | Signed withdrawal payload |
action.action | string | Yes | Action type from /createWithdrawal |
action.typedData | object | Yes | Original typedData from /createWithdrawal |
action.signature | string | Yes | User’s signature of the typedData |
Response 202
{
"result": {
"action": "Withdraw",
"success": true
}
}
| Field | Type | Description |
|---|
result.action | string | Action type |
result.success | boolean | Whether the withdrawal was accepted |
result.error | string | Error 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()