Build withdraw payload
Execution
Build Withdraw Payload
Build a signed canonical payload to withdraw USDC collateral from a perpetual DEX account back to the user’s wallet.
POST
Build withdraw payload
Lighter-only. Gains withdraws collateral by closing positions — there is no separate withdraw endpoint. Skip this for Gains.
Lighter withdraw payload shape
The response’spayloadStr is an envelope whose payload includes an L1 authorization challenge:
- Parse
payloadStr. - Sign
payload.MessageToSignwith the user’s wallet (standard EIP-191personal_sign). - Set the resulting hex on
payload.L1Sigand deletepayload.MessageToSign. - Re-stringify the envelope →
finalPayloadStr. - Sign
`api/2/perp/execute-v2-${timestamp}-${finalPayloadStr}`and call/2/perp/execute-v2with thatpayloadStr(no top-levelsignedTx).
Request Body
Must be
lighter.Lighter chain (e.g.,
lighter:301).USDC amount as a decimal string (e.g.,
"100"). Must be positive.Authentication
Every/2/perp/payloads/<action> endpoint verifies the caller by requiring two extra fields in the request body alongside the action parameters:
Unix timestamp in milliseconds. Must be within 30 seconds of server time. Older timestamps are rejected to prevent replay.
Hex signature (EIP-191
personal_sign) of the message `${endpoint}-${timestamp}`, where endpoint is the path of this endpoint without the leading slash (e.g., for this page: api/2/perp/payloads/<this-action>). The recovered signer address becomes the user for the request. Single-use — replay returns 403 signature already used.Authentication errors
| Status | message |
|---|---|
| 403 | timestamp expired — timestamp older than 30s |
| 403 | signature already used — replay attempt |
| 400 | zod validation failed — timestamp/signature shape invalid |
Response envelope
Every/2/perp/payloads/<action> endpoint returns the same envelope shape. You pass these fields verbatim into POST /2/perp/execute-v2 to execute the action.
Top-level shape. Successful (2xx) responses return
{ data: { ... } }. A success: true flag is only present inside the body of execute-v2’s response, not on the payload-build endpoints. Parse defensively: read body.data, then check for the action-specific fields you need (e.g. data.payloadStr).Endpoint-specific errors
| Status | message |
|---|---|
| 400 | withdraw payload generation failed — insufficient free margin or DEX refusal |
Example — Lighter withdraw 100 USDC
Body
application/json