V2 Integrator API
Get Enroll Signable Message (Stage 1)
Stage 1 of the two-stage enrollment flow — returns a signable session-key message for the user to sign in their wallet.
POST
Stage 1 of the two-stage enrollment flow. Validates that the
strategyId
belongs to your tenant, peeks the user’s next available account index, and
returns the signable message the user must sign plus the round-trip values
(flowId, accountIndex, agentAccountId) that stage 2
(POST /v2/enroll) will need.
Wallet addresses are exchanged as CAIP-10
account identifiers. For EVM, ownerAccountId and agentAccountId use the
chain-agnostic form eip155:0:<address> — a single wallet works on every
EIP-155 chain.
For EVM smart-contract wallets, pass accountType: "ERC1271" in both stages.
ERC-1271 enrollment returns an EIP-712 typed-data message and currently
requires exactly one EVM chainId per enrollment signature. Omit
accountType or pass "ECDSA" for the existing EOA/multichain path.
Solana (SVM) enrollment
A Solana-native user enrolls withownerAccountId set to a solana: CAIP-10
(solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:<base58>) and chainIds: [1399811149].
The SVM flow mirrors how a Solana user joins the platform: the first portfolio
for a given (tenant, user) pair creates a Swig smart wallet (the user’s
wallet key is its root authority — a Solana key for a solana: owner, an EVM
key for an eip155: owner; see below); subsequent portfolios reuse the same
Swig. Each portfolio is a sub-account of that Swig, and the sub-account
address is the deposit address the user funds. The pooled agent is attached
at create, so the portfolio is operable immediately.
Solana-rooted users (Model B)
Because creating the sub-account is an on-chain action, stage 1 returns a serialized Solana transaction (solanaTransaction) for the user to sign with
their wallet — instead of signing message. The response also includes:
solanaTransaction— base64 transaction; the user signs it and round-trips the signed bytes toPOST /v2/enrollassignedSolanaTransaction. It carries a recent blockhash, so sign and submit promptly.depositAccountId— CAIP-10 of the sub-account the user sends funds to.swigRoleId— the Swig role that owns the sub-account (1for the first portfolio, higher when reusing an existing Swig).reusedSwig—truewhen an existing Swig PDA for this (tenant, user) is reused,falsewhen a new one is created.
EVM-rooted users (Model A)
A user whose primary wallet is EVM enrolls into the same Solana sub-account model by settingownerAccountId to eip155:0:<address> with
chainIds: [1399811149]. Their secp256k1 (EVM) key becomes the Swig root.
Stage 1 returns the targets the client needs to build the authorization:
swigAccountId— CAIP-10 of the parent Swig PDA.depositAccountId/swigRoleId/reusedSwig— as above.agentAccountId,accountIndex,flowId— round-tripped to stage 2.
message is an ecdsa digest that is informational only — the user
does not sign it. The client builds a slot-bound Swig add-authority
payload (from swigAccountId + agentAccountId + a freshly captured slot),
personal_signs its hash, then sends userSecp256k1PublicKey + signature +
currentSlot to POST /v2/enroll. Capture the slot and submit promptly — Swig
enforces a slot window. There is no create-only fallback; these fields are
required.
- Auth:
x-api-keyheader (required) - Scope:
enroll:write
flowId is the idempotency anchor for the matching
POST /v2/enroll call — it is valid for 24 hours. Re-submitting the same
flowId on stage 2 replays the cached response.
The accountIndex is peeked, not reserved: repeated stage-1 calls for
the same user return the same candidate index, and the index only advances
when stage 2 commits successfully. Retries, abandoned flows, and tests do
not burn account indices.
Unknown chains in chainIds are rejected with 400 before any enrollment
state is created — the allowed list is in the error details.
Common error responses:
400when the request body is invalid, thestrategyIddoesn’t exist or your API key cannot access it, orchainIdscontains an unsupported chain401whenx-api-keyheader is missing or the key is invalid403when the API key lacks theenroll:writescope500on unexpected server errors