Build create-account payload
Perps Execution
Build Create-Account Payload
Build a signed canonical payload to create/provision the user’s account on a perpetual DEX (e.g., register a Lighter sub-account or API key).
POST
Build create-account payload
Lighter-only. Gains has no provisioning step — accounts are implicit. Skip this endpoint for Gains.
(L1 address, accountIndex) after the user’s first deposit so subsequent trades, withdrawals, etc. can authenticate against Lighter.
Account lifecycle on Lighter
A wallet (EOA) is not a Lighter account by default. Lighter only registers an account on-chain after the L1 address makes its first USDC deposit (≥ 5 USDC, a Lighter-side requirement). Once the deposit settles, Lighter assigns anaccountIndex to that L1 address. The integrator must then call this endpoint with the discovered accountIndex to provision an API key + auth token — without it, every other Lighter perp endpoint (create-order, close-position, withdraw, …) will fail.
End-to-end first-time setup:
- Deposit ≥ 5 USDC via
/2/perp/payloads/deposit→ submit via/2/perp/execute-v2→ poll/2/perp/check-processuntil success. - Discover the
accountIndexby polling Lighter’s account-lookup endpoint (the bridge takes a few seconds to settle on L2):Response shape (success):{ "code": 200, "accounts": [{ "account_index": <number>, ... }] }. Poll every ~1s untilaccounts[0].account_indexis present.Coming soon. Mobula will expose a proxy endpoint so integrators don’t need to call Lighter directly. For now, hit Lighter’s URL above. - Provision the API key by calling this endpoint with the discovered
accountIndexand submitting via/2/perp/execute-v2. The response payload may carrypayload.MessageToSign— sign it, setpayload.L1Sig, deletepayload.MessageToSign, re-stringify, and sign execute-v2 over the new string. - The user’s wallet can now call all Lighter trade/withdraw endpoints.
Request Body
Must be
lighter.Must be
lighter:304 (the only chain that accepts Lighter create-account today).Lighter sub-account index (non-negative integer). Discovered via the Lighter
/api/v1/account?by=l1_address&value=<EOA> lookup after the first deposit settles.Lighter API key slot to provision (≥ 0). Pick any unused slot. Defaults server-side if omitted.
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 | accountIndex must be a non-negative integer for lighter create-account — missing or invalid accountIndex |
| 400 | Invalid chainId "<value>" for lighter create-account — chainId other than lighter:304 |
| 400 | create-account payload generation failed — Lighter rejected provisioning (e.g., slot already in use) |
| 501 | payload action "create-account" not implemented yet — dex other than lighter |
Full flow — provision a Lighter sub-account end-to-end
Assumes the wallet has already deposited ≥ 5 USDC and you have polled Lighter to discover itsaccountIndex. Snippet shows step 3 of the lifecycle above.
Helper — discover accountIndex after a deposit
Body
application/json
Unix ms timestamp; must be within 30s of server time.
Hex signature of {endpoint}-{timestamp}. Recovered signer becomes the request user.
Available options:
lighter Must be lighter:304 (only chain that accepts Lighter create-account today).
Available options:
lighter:304 Lighter sub-account index. Discover via Lighter's /api/v1/account?by=l1_address&value= after the first deposit settles.
Required range:
x >= 0Lighter API key slot to provision. Pick any unused slot. Defaults server-side if omitted.
Required range:
x >= 0