Skip to main content

Overview

The API provides multi-chain wallet management for EVM-compatible blockchains. Each user can hold multiple wallets across different chains, with two distinct wallet types:
  • EOA (Externally Owned Account) — user-controlled wallets added through verified ownership
  • Safe (Smart Wallet) — smart contract wallets persisted under a user’s primary EOA
Every user has a primary EOA wallet that serves as their main identity on-chain. The Safe paired with that EOA is provisioned through one of three cohort-specific flows configured at the SIS environment level — see Onboarding cohorts. The EOA signs. The Safe holds. The two are paired — always on the same chain.
Safe creation depends on your environment’s cohort, but the surface is uniform: GET and POST /v0/user/me/onboarding/safe serve every cohort — the response carries a mode discriminator and a cohort-specific config block. The POST body is a shape-only payload (no mode field — the cohort is derived server-side).
  • mode=agent_create2 (default): Sumvin’s signing service deploys the Safe automatically and attaches an agent signer. Clients call POST with an empty body {} and receive 204 No Content; the workflow does the work.
  • mode=user_signed_deploy: the user signs the Safe deployment UserOp themselves. Recommended for partners who want user-controlled wallets without an agent signer.
  • mode=byo: the user submits the address of an existing on-chain Safe (Bring Your Own Safe).
See Submitting the Safe step for the per-cohort POST shapes, idempotency support, and rate-limit details.

Wallet Ownership Verification

Before a wallet can be registered, the user must prove they control it. The API supports three methods depending on your authentication provider and wallet type.

Method 1: Dynamic Credential

If your platform uses Dynamic Labs for authentication, wallet ownership is verified automatically through the user’s verified credentials.
Building a React UI? useCreateWallet() from our TanStack Query patterns wraps this call with the production request() wrapper and frontend:wallets:create caller metadata.
The API retrieves the verified wallet address and chain from Dynamic’s API using the credential ID in the user’s JWT. If the credential is valid and the wallet address has been cryptographically verified during sign-in, the wallet is created. Response: 201 Created

Method 2: SIWE (Sign In With Ethereum)

For platforms that don’t use Dynamic Labs, or when you need standalone wallet verification, use the SIWE challenge/verify flow. Step 1: Request a challenge
Response: 200 OK
Step 2: Sign the message with the wallet’s private key and submit
If the signature is valid, the wallet is created automatically. Response: 201 Created The response body matches the wallet object from Method 1.
SIWE challenges expire after 10 minutes. If the challenge expires before verification, request a new one.

Method 3: Manual Safe Creation

For advanced use cases where you need to create a Safe wallet directly (e.g., for agent-controlled wallets), use the manual Safe creation flow. Step 1: Get Safe configuration for the target chain
Response: 200 OK
Step 2: Build and sign the Safe creation transaction, then submit via the RPC endpoint The submit endpoint is the same one used for every on-chain action a Safe takes — it accepts a signed ERC-4337 UserOperation, sponsors gas, and returns a hash you can poll. See Submitting UserOperations for the full lifecycle, including how to interpret the terminal included, failed, and rejected statuses.
Response: 202 Accepted
Step 3: Register the wallet with the transaction hash for on-chain validation
The API validates the transaction on-chain to confirm the Safe was created by the authenticated user, then registers it. Response: 201 Created
Manual Safe creation is an advanced flow. Most integrations should use Method 1 (Dynamic credential) or Method 2 (SIWE). Only use this method when you need programmatic control over Safe deployment parameters.

Setting a Primary Wallet

Promote a wallet to primary status. This may trigger asynchronous Safe creation if no Safe exists on that chain:
Using TanStack Query? useUpdateWallet() shows the optimistic mutations pattern end-to-end — it updates the wallet list in onMutate, rolls back in onError, and invalidates queryKeys.wallets.all in onSettled.
If a Safe already exists on that chain, you get 200 OK. If a new Safe needs to be deployed, you get 202 Accepted with a safe_creation_event_id:

Primary chain is locked once a Safe is deployed

Once a Safe smart wallet is persisted for a user (via the byo_safe step, the safe_deploy user-signed flow, or agent-driven Safe creation), the user’s primary chain is locked. Promoting an EOA on a different chain to primary returns 400 Bad Request with error code WAL-400-004 (Primary Chain Locked):
This guard prevents an in-place chain switch from orphaning the user’s existing Safe. If you genuinely need a Safe on a different chain, that is a separate flow — contact your Sumvin point of contact, this isn’t currently a self-serve operation.

Polling for Safe Creation

When you receive a 202, poll the user profile to check Safe creation progress:
In React, useUser() already serves the profile with stale-while-revalidate — instead of a manual setTimeout loop, set a short refetchInterval until safe_creation_status === 'completed'.
The safe_creation_status field on the user tracks progress. Once completed, the primary_smart_wallet_address field contains the deployed Safe address.

Wallet Types

EOA wallets are standard Ethereum accounts controlled by a private key. Your application registers them after ownership verification so the API can track balances and transactions. Safe wallets are smart contract wallets deployed by the system (or manually via Method 3). They provide multisig capabilities and are paired with the user’s primary EOA on the same chain. System-created Safe wallets cannot be deleted — they are managed entirely by the system. A third kind of record is stored alongside these but is not a wallet type you create. Signer keys are addresses recorded as signers on the account’s Safe rather than wallets the account holder chose. A CLI mandate key — the key the Sumvin CLI holds locally so a developer can sign mandates as the user — is the one kind in use today. They are kept apart from the rest of the account’s wallets:
  • They are omitted from GET /v0/wallets and from GET /v0/user/me?expand=wallets, so those lists hold only wallets the account holder can transact from. Filters such as is_eoa=true do not bring them back.
  • They remain readable at GET /v0/wallets/{wallet_id} by their own wallet ID.
  • They cannot be deleted. DELETE /v0/wallets/{wallet_id} refuses any wallet carrying a signer role with WAL-403-005, because soft-deleting the record would not remove the key from the Safe on chain — the account would read as though the key were revoked while it could still sign.
  • They do not count as wallets the account holder owns for authorization purposes. A contract deployed by a signer key is not evidence the account holder deployed it, so POST /v0/wallets with method=txn_hash returns WAL-403-004 in that case.

Multi-Chain Support

The API supports wallets across all major EVM-compatible chains: Each wallet is scoped to a single chain. A user can have wallets on multiple chains, but the primary EOA and its corresponding Safe must be on the same chain.

Safe Creation Flow

When you set a primary EOA on a chain where no Safe exists, the system deploys one asynchronously.

Safe Creation Statuses

Applies to the ai_agent cohort only. Agent-deployed Safe creation requires an active agent signer on the target chain. If signer setup is still in progress, setting a primary wallet returns 424 Failed Dependency. Wait for onboarding to complete before setting a primary.Users in the user_signed_deploy or byo_safe cohorts have no agent signer and never see this 424. See Onboarding cohorts.

Endpoints

List Wallets

Returns all wallets for the authenticated user. Supports filtering and expansion.
Building a React UI? useWallets(filters?) from our query patterns gives you a 5-minute staleTime and isNonRetryable retry gating. Pair it with useWalletAssets(walletId) for per-wallet balances and useWalletBalances(walletId) for the aggregated summary.
Query parameters: Response: 200 OK

Get Wallet

Returns full details for a specific wallet. Query parameters: Response: 200 OK

Create Wallet

The create wallet endpoint accepts different request bodies depending on the ownership verification method. See Wallet Ownership Verification above for the full flow for each method.
Method 1 — Dynamic credential: Method 2 — SIWE: Wallet creation happens automatically when the SIWE verify call succeeds. No separate wallet create call is needed. Method 3 — Manual Safe (with tx hash): Response: 201 Created Returns the created wallet with _links including set-primary and delete actions.

Update Wallet

Updates wallet properties or promotes to primary status. Request body: Response: 200 OK when the update is synchronous, 202 Accepted when Safe creation is triggered. When the response is 202, it includes:
  • safe_creation_event_id — event ID for tracking
  • _links.safe-status — link to poll for Safe deployment completion

Delete Wallet

Soft-deletes a wallet. The record is retained for audit purposes but no longer appears in lists.
In React, useDeleteWallet() optimistically removes the wallet from the list and invalidates the entire queryKeys.wallets.all subtree on settle (success or rollback) — see the invalidation strategy page for the full key pyramid.
Response: 204 No Content Primary wallets cannot be deleted. Set another wallet as primary first, then delete the old one.

List Wallet Assets

Returns all token balances held in a specific wallet, with USD valuations. Response: 200 OK

List Asset Transactions

Returns paginated transactions for a specific asset in a wallet. Query parameters: Response: 200 OK
Pagination links (next, prev) are included in _links when applicable.

Get Balance Summary

Returns an aggregated balance summary for a wallet, including all assets with USD valuations. Response: 200 OK

Integration Patterns

Choosing a Verification Method

Handling Async Safe Creation

When the wallet update returns 202, implement a polling loop: PATCH /v0/wallets/{wallet_id} — Update wallet (may return 202 when Safe creation is triggered).
The typical Safe deployment takes 10–30 seconds depending on chain congestion.

Building a Wallet Selector

Fetch all wallets and group by type:
Responses include _links for discoverable navigation. Non-primary wallets include set-primary and delete action links. Primary wallets omit these since the actions are not permitted.

Error Handling

All error responses follow RFC 7807 Problem Details. See Error Handling for the full reference.

Wallet Error Codes

GET /v0/wallets — List wallets.

Asset Error Codes

Reference Tables

Wallet Response Fields

Wallet Asset Fields

Asset Transaction Fields

Next Steps

Wallet management sits downstream of the onboarding state machine — run onboarding to completion before standing up wallets, and confirm your authentication against the Platform API JWT model. The wallet is not the identity. The Safe on it is — and the Safe is what every agent, card, and credential anchors to.