Build deposit payload
Execution
Build Deposit Payload
Build a signed canonical payload to deposit USDC collateral into a perpetual DEX account (Lighter) or bridge USDC into a Gains account.
POST
Build deposit payload
Lighter-only. Gains has no deposit endpoint — collateral on Gains is sent directly with each
create-order. Skip this for Gains.originChainId to the Lighter L2 account via a multi-step bridge route.
Deposits are eventually consistent and tracked asynchronously — the execute-v2 response carries a processId you poll via /2/perp/check-process.
First-time deposits register the account on Lighter. If the EOA has never deposited on Lighter, this call must transfer ≥ 5 USDC (a Lighter-side requirement). Once the bridge settles, Lighter assigns an
accountIndex to the L1 address — needed by /2/perp/payloads/create-account and every subsequent trade/withdraw call. See the create-account page for how to discover the accountIndex afterwards.Lighter deposit payload shape
The response’spayloadStr is a canonical envelope whose payload carries a bridge route with one or more transaction steps:
- Parse
payloadStr. - For every step with
kind === "transaction"and everyitemwhosestatus !== "complete", sign the tx with the user’s key onitem.data.chainId. - Push each signed hex string (in order) into a new array
payload.signedTxs. - Re-stringify the envelope →
finalPayloadStr. - Sign
`api/2/perp/execute-v2-${timestamp}-${finalPayloadStr}`and call/2/perp/execute-v2with thatpayloadStrand no top-levelsignedTx.
Request Body
Must be
lighter.Destination Lighter chain. Must be
lighter:304 — only id the router accepts for deposit today.EVM chain holding the user’s USDC. Confirmed working:
evm:42161 (Arbitrum), evm:8453 (Base). Other EVM chains may resolve — open an issue if you need one that isn’t listed.USDC amount as a decimal string (e.g.,
"250" or "100.5"). 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 | deposit payload generation failed — bridge unavailable, insufficient USDC, or DEX refusal |
Example — Lighter bridge from Arbitrum
Body
application/json
Available options:
lighter Destination Lighter chain (lighter:301 or lighter:304).
Source chain holding the user's USDC.
USDC amount as a decimal string (e.g., "250"). Must be positive.