createAction and executeAction.
For trading actions, the Trading pages document the convenience wrappers (placeOrder, cancelOrders, etc.) that handle createAction, agent-signing, and executeAction automatically. Those wrappers are the supported public surface for trade dispatch — createAction/executeAction are documented here for completeness and for action types that don’t have a dedicated wrapper. Withdrawals and account setup use the same authorization model, but the SDK exposes higher-level helpers (withdraw, checkSetup / executeProviderSetupAction) that should be preferred. Session-only actions execute directly through the provider plugin and intentionally skip executeAction.
Pattern
- Create — call
createAction()with the action type and params. Returns one or moreActionSteppayloads. Each step’s shape depends on the action’ssigningMethod: EIP-712 typed data, a WASM-signer blob, an EVM transaction, an HMAC request, a SIWE challenge, or a client-only session marker. - Authorize — let the provider plugin sign or execute each step according to
ProviderAction.signerandsigningMethod.USERmeans the user’s wallet or consent must act (usually the wallet, or a client-held provider session forsessionsteps);SDKmeans the SDK fulfils the step with its own credentials. UseexecuteProviderSetupActionfor setup steps instead of embedding scheme-specific logic. - Execute — call
executeAction()with signed EIP-712, WASM, EVM, or HMAC payloads.sessionand SIWE steps are completed client-side by the provider plugin and never sent: they produce no signed step to submit, and/executeActionrejectssiweLogin.
createAction
Build action payloads for signing.Parameters
Returns
CreateActionResponse — { actions: ActionStep[] }.
ActionStep is a discriminated union by structural shape — the SDK dispatches to the correct signer based on which key is present. The variant that comes back is determined by the action’s signingMethod on the provider descriptor (see SigningMethod).
Eip712ActionStep — EIP-712 typed-data flow (Hyperliquid; most actions):
WasmBlobActionStep — WASM signer flow (Lighter):
EvmTxActionStep — on-chain EVM transaction (e.g. Lighter deposit):
HmacActionStep — provider request signed SDK-side with a client-held API key:
SiweActionStep — ERC-4361 login challenge. The provider plugin completes it client-side; it is never sent to executeAction:
SessionActionStep — provider-session marker completed client-side, not sent to executeAction. Ondo’s createDepositAddress carries a public { network: 'ethereum', symbol: 'USDC', depositDestination: { wallet: 'margin' } } policy marker; acceptProviderTerms, registerApiKey, and addWithdrawalAddress use an empty marker (session: {}). A session-signed action can also be wire-shaped as a request-bearing step instead of a marker — Ondo’s setReferrer carries a real { method, path, body } request that the SDK submits directly with the session credential rather than HMAC-signing it.
On Hyperliquid,
placeOrder with a leverage param always returns an updateLeverage step ahead of the placeOrder step; the SDK never compares leverage with the current setting. Omit leverage to leave the venue setting untouched.EvmCall
ThetxParams on the EVM-transaction step variants is an EvmCall:
executeAction
Submit signed action payloads.executeAction is the HTTP call. It resolves with the backend’s 202 report and does not throw for a failed or indeterminate step. A request or transport error throws. See Execution reports.
Parameters
SignedActionStep is a discriminated union that mirrors ActionStep — each variant carries the original payload plus its signed artefact.
Eip712SignedActionStep:
WasmBlobSignedActionStep:
EvmTxSignedActionStep:
HmacSignedActionStep:
SiweSignedActionStep ({ action, siwe, signature }) exists in the SignedActionStep union, but the SDK never submits it: siweLogin is completed client-side and /executeAction rejects it.
Returns
ExecuteActionResponse — { results: ActionResult[] }:
Each ActionResult:
Execution reports
ExecuteActionResponse.results is an execution report: one ActionResult for each step that the backend attempted, in execution order. @lifi/perps-types exports UserActionStatus with five values, and @lifi/perps-sdk exports isSubmittedOrAccepted(result).
Three axes are separate:
- HTTP status.
202means that the backend processed the request. It does not mean that the venue accepted a step. - Action status.
result.statussays how far each step went. - Error cause.
result.errorCodeandresult.errorsay why a step failed or is uncertain.
- Execution stops at the first step that is
FailedorIndeterminate. The later steps are not attempted and have no result. - Every member of an attempted atomic batch has its own result. Lighter sends an order and its trigger orders as one batch.
- Two steps with the same
actionkeep two results. Do not key the results byaction. - Results of earlier acknowledged steps stay in the report after a later step fails.
- For a client-executed step, the report holds the SDK result before the backend results. Lighter token-authenticated venue calls and confirmed EVM legs are examples.
results.every(isSubmittedOrAccepted) hides the cause of a stop, and a blind retry can repeat an order that the venue already took:
- A returned result with status
Failedis a confirmed refusal. TheerrorCodeis the venue or LI.FI classification. - A thrown error is a request, signing or transport failure with no report. The SDK did not get a result for it. See Error Handling.
onExecuteResults callback, the SDK throws PerpsExecutionError. Its response.results holds every result known at that point, and cause holds the original error. If no result is known, the original error propagates unchanged.
The Submitted status does not mean that the SDK pushes later verification updates to your code. Track the outcome with the account reads, for example Order Status.
Setup, options and revoke
executeProviderSetupAction, executeProviderOption and executeProviderRevoke return Promise<ExecuteActionResponse>. They return the report and do not return void. They do not throw for a Failed or Indeterminate step, so read status on each result. They throw PerpsError for the cases in their method reference, and PerpsExecutionError when a later stage fails after a result is known. submitOnboarding, createReferralCode and executeMetaAction follow the same rule.
PerpsProviderPlugin.signActions returns { signed, executed }. executed holds the results of steps that the plugin executed on the client. The client puts them in the report before the executeAction results, and it submits signed only when every executed result is Submitted or Accepted.
Release and migration
The status contract is a coordinated breaking release. It replaces thesuccess boolean on ActionResult.
Release requirements:
- Install matching versions of
@lifi/perps-sdk,@lifi/perps-typesand the provider packages.@lifi/perps-sdk27.0.0depends on@lifi/perps-types24.0.0. Mixed majors read a different result shape. - Update the backend and widget consumer pins in the same release. Do not deploy the new backend beneath a consumer that still reads
success: the newActionResulthas no such field. - This release changes the
ActionResultresponse of/v1/perps/executeActionin place and adds no new API version. If an existing external consumer must keep the old shape, the API needs an explicitly versioned boundary, and this release does not provide one.
Action Types
All action types from the provider’ssetup and actions arrays can be used with createAction/executeAction. The relay of the action descriptor says where each signed step goes: API steps go to executeAction, and CLIENT steps go from the client to the venue. See Providers.
For parameter schemas per action type, see Actions API. For the high-level convenience wrappers that handle agent signing automatically, see SDK / Trading.
API Reference: POST /createAction, POST /executeAction
App-level onboarding
The threeMeta actions above are provider-independent: the SDK sends them with the META_PROVIDER ('meta') sentinel instead of a real provider key, so the backend dispatches them without resolving a venue plugin. They carry no ProviderAction descriptor and are always signed as EIP-712 typed data with the end-user’s wallet — never with a provider’s agent, native key, or session credential.
PerpsClient exposes three matching methods:
PerpsError when no user wallet is configured, when the backend returns more than one step or a non-EIP-712 step, or when the request fails; a wallet signature refusal propagates as the wallet’s own error. A refused or uncertain step is a result in the report, not an exception. Read status on each result.
Use getTermsAcceptance to check the current terms version and whether an address has already accepted it before calling submitOnboarding.