Skip to main content
A working SDK integration is step one. A production-quality integration handles edge cases, secures credentials, and recovers from failures.

Credential security

Your sk_live_ API key grants full access to your organization’s accounts. Treat it like a database password.
  • Store API keys in environment variables or a secrets manager
  • Never log the full key value
  • Create separate keys per environment (dev, staging, production)
  • Rotate keys on a regular schedule, not only after incidents
Your publishable key (pk_live_) is safe for client-side code. It identifies your account type but cannot read or modify account data on its own. The SIWE session provides the authorization layer.
Rotating your organization’s signing key invalidates all active SIWE sessions. Plan key rotation during low-traffic windows.

Session management

Deposits and withdrawals run through stateful sessions. One active session per account at a time. Re-quoting: Call the same quote method again on the current OPEN session to change the amount, token, chain, or current price. Do not create a new session for re-quotes.
Force reset: Use forceReset: true only when you need to cancel the existing session entirely. This includes switching between deposit and withdrawal in the high-level frontend SDK. Do not use it to update a same-type quote. Session expiration TTLs: Build your UI to show quote expiration and allow re-quoting while the session is OPEN. New submissions move directly from LOCKED to SETTLED when the API accepts the transaction hashes. SETTLED confirms hash ingestion, not receipt verification. Use balances and positions to confirm indexed on-chain activity. The SDK retains SUBMITTED and FAILED for historical sessions. When resuming a legacy SUBMITTED session, an executor polls until it reaches a terminal state. Do not design new flows around entering SUBMITTED.

Transaction handling

The frontend and server execution helpers have different responsibilities:
  • sdk.execute() in @blend-money/fe derives wallet clients, submits Safe transactions using the configured paymaster registry, and records their hashes.
  • client.sessions.execute() in @blend-money/node orchestrates the session lifecycle, but your submitActionPlan callback owns signing and on-chain submission.
Withdrawals can produce multiple action plans, one per source chain. The server executor invokes submitActionPlan sequentially for each plan. Keep your callback idempotent and return every submitted hash with its chainId.
The server response normally returns SETTLED immediately after hash submission. SDK 3.0.1 can still surface a SUBMITTED status callback for compatibility, but new server sessions do not persist that intermediate state. Paymaster sponsorship. Only the frontend SDK accepts paymaster configuration. Configure its required per-chain registry with the current Pimlico and Alchemy helpers.
Later registry entries replace earlier entries for the same chain. BlendServerSdk has no paymaster option. Its submitActionPlan callback is responsible for signing, gas, and transaction submission.

Conflict handling

A 409 with FLOWPLAN_CONFLICT means a rebalance is in progress on the account. The system is moving funds between vaults. Do not retry blindly. Surface this as a product-level message and let the user retry after the account settles.
Flow plan conflicts only affect withdrawals. Deposits are not blocked by active rebalances.

Safe deployment

Safes are deployed lazily. Creating an account does not deploy the Safe on every chain. The chainsDeployed array in the account response tells you which chains are live right now. This catches most people off guard: signing in or looking up an account does not deploy a Safe. The chainId in signIn() is only for the SIWE challenge message. Deploying a Safe is always a separate safe.request() call, and it happens asynchronously. Before your first transaction on any chain, check deployment and request it if needed:
safe.request() is fire-and-forget. Deployment happens in the background. Poll safe.resolve() until the status changes to "validated" before executing transactions.
Your Safe has the same address on every chain. Once deployed on one chain, you can deploy on any other chain and get the same address. The CREATE2 determinism makes cross-chain reuse automatic. safe.resolve() returns one of four statuses:

Error recovery

Both execution helpers read the current server session before deciding what to do next. Reusing the same intent resumes from the state the API recorded. Make on-chain submission idempotent because a process can stop after broadcasting a transaction but before recording its hash with Blend.
The derived wallet client must be configured for chainId with an attached account whose address equals signerAddress. For server integrations, import SdkError from @blend-money/node and retry client.sessions.execute() with the same intent ID. A retry must not broadcast a duplicate transaction when your own records already contain its hash. isRetryable() returns true for HTTP 429, 5xx status codes, and network errors (status 0). The built-in HTTP client already retries with exponential backoff and jitter, so you only need manual retry logic for application-level recovery.

Frontend SDK

See the full frontend SDK reference.

Server SDK

See the full server SDK reference.
Last modified on July 24, 2026