Skip to main content
A multisig vault is an on-chain account controlled by a list of owner addresses and a signature threshold. Spending from it requires an order approved by at least threshold owners. Every chain implements this differently: Gnosis Safe on EVM, Squads v4 on Solana, native account permissions on Tron, a SignerList on XRP, a P2WSH script on Bitcoin, a native script on Cardano. The SDK normalizes creation and activation behind createMultisig / activateMultisig, but the number of round trips and the client-side work differ substantially per chain. That is the main subject of this page.
Personal Vaults can have owners on a hardware wallet. Organization Vaults cannot. A Trezor cannot sign TRON or XRP Vaults, and the Bitcoin and Cardano Vault keys of a hardware account come from prepareHardwareVaultKeys. See Hardware Wallets.

Prerequisites

Vault creation and activation run on the same v2 wallet session as personal wallets (see Key Management):
Creating a vault on SOL, TRON or XRP requires both userRef and walletPassword on the call. Either one missing raises InvalidInputError. EVM, BTC and ADA creation does not need them.

Bitcoin and Cardano need a cosigner pool

On Bitcoin and Cardano a vault does not reuse an owner’s personal wallet key. Each owner contributes a key from a separate derivation subtree — BIP-48 for Bitcoin, CIP-1854 for Cardano — and those are what the P2WSH descriptor and the native script are built from. Only the owner can produce them, because they come from that account’s recovery phrase. So the backend keeps a pool of them per account, filled by the client, and every vault created claims one row from the pool of every owner it names. The pool therefore drains over the account’s lifetime, not just once at creation.
With an empty pool, creating a Bitcoin or Cardano vault that names this account as an owner fails with 409 and the code COSIGNER_KEYS_EXHAUSTED. Nobody can refill it on the owner’s behalf.
Refill it from any unlocked session:
Call it after unlocking, and again after creating a vault. It starts with a read and derives only what the backend reports as short, so it is cheap when there is nothing to do. Only public material leaves your process: an account-level xpub and a master fingerprint for Bitcoin, a payment and a stake key hash for Cardano — never a private key.
unconsumed is how many vaults this account can still join on that chain. Read it before offering a vault-creation screen if you want to warn early rather than fail at submit. isCosignerPoolChain answers whether a chain draws on a pool at all, so you can skip the read where it cannot matter. For the Master of an organization with its own recovery phrase, the organization has a pool of its own. Without ownerKind the call fills the personal pool and, when the organization’s phrase is active and confirmed, the organization’s pool too. Pass ownerKind: 'personal' | 'organization' to fill one of them.
The top-level inserted and pools are those of the first pool that succeeded, the personal one first. One pool failing does not stop the other; the call throws only when every pool failed. If the personal phrase was replaced in the web app after the session cached it, the top-up is refused instead of filling the pool with keys of the old phrase.
Only wallets derived from the account recovery phrase draw on the pool. A wallet imported by private key has no derivation tree, so it contributes its single public key instead and needs no pool. Such a vault is still fully spendable, but it cannot be imported into an external wallet like Sparrow or Eternl.

Method reference

feeQuote is required by ActivateMultisigInput, so it has to be present. Price it with estimateFee({ txType: TransactionEstimatingType.ActivateMultisig, payload: { from, multisig } }) See Multisig Network Fees. On EVM the gas actually spent comes from the gasLimit / gasPrice overrides, not from feeQuote.

Owners and threshold

CreateMultisigInput:
  • Every entry in owners is validated with assertValidAddressForChain before any request goes out; a bad address fails locally with the field name (owners[1]) in the message.
  • owners[0] is used as the creator address for SOL, BTC, ADA and XRP creation.
  • ownerLabels is optional on every chain. When present it must have exactly one entry per owner, otherwise InvalidInputError is raised before any request. Each label is trimmed; an empty one means “no name”, and one longer than 100 characters is rejected with Name must be 1–100 characters. These are the creator’s names: every member sees them as the default until they set their own (see Owner names). They also go into the vault’s recovery file.
  • Every owner must belong to the account’s current recovery phrase. A wallet whose accessState is archived or access_lost is refused with VAULT_OWNER_NOT_CURRENT_GENERATION, and details.walletAddresses names which ones. See Wallet generations.
  • chainIds is optional. Omitted, the SDK picks the default chain id for each chain based on the network it was constructed with.
  • For EVM only, chainIds may hold several chains. One vault record is created per chain and createMultisig returns a MultisigsItem[]. Every other chain uses chainIds[0] and returns a single MultisigsItem.
  • XRP caps the signer list at 8, and the SDK raises InvalidInputError when an owner-update order would exceed it.
  • On EVM, removing an owner is rejected client-side when the vault would drop below 2 owners (Vault should have at least 2 owners).

Core types

MultisigsItem.status is the literal union 'created' | 'execution' | 'deployed'. The exported MultisigStatus enum (PENDING = 'pending', ACTIVE = 'active', INACTIVE = 'inactive') is a separate type that the vault record does not use, so do not compare multisig.status against it. Use isDeployed for a plain “is it live on chain” check.
Read shapes:
Both read shapes are grouped: one row per vault address, with the per-chain records in data. A single-chain vault still arrives as data[0], which is where factoryAddress, params.deployData, owners, and threshold live.

Vault activation shares

Solana, Tron and XRP vaults are activated by a key that is not any owner’s wallet key. Creating the vault generates that secret in your process and splits it the same 2-of-3 way as a wallet key (see Key Management). The backend alone can never rebuild it. You do not manage any of this by hand:
  • Creating a vault splits the secret and stores the device share under the vault id when you pass userRef.
  • Activating from the same host rebuilds the secret from the device share.
  • Activating from a different host needs walletPassword on activateMultisig, so the secret can be rebuilt from the two server-side shares. Without it you get DEVICE_SHARE_REQUIRES_PASSWORD.
  • The reconstructed secret is wiped as soon as activation finishes, on every path.
The recovery share is stored under the creating user’s account. A co-owner who did not create the vault cannot rebuild the activation secret and cannot activate it.

Password rotation

changeWalletPassword rotates vault activation shares alongside wallet shares. See Key Management for the full result shape.

Creating and activating, per chain

Vaults fall into two groups. On EVM, Solana, Tron and XRP the vault must be activated on chain before it can hold or move funds. On Bitcoin and Cardano the address is spendable as soon as it is funded, and there is nothing to activate.
On XRP, activation permanently disables the account’s master key. After it, the account can only be moved by the signer list. This cannot be undone.
Calling activateMultisig on Bitcoin or Cardano throws, because there is nothing to activate. For those two chains, changing the owner set or the threshold means creating a new vault and moving the funds.
A full EVM create-and-activate:
The other activating chains take the same call with their own chain value. Pass walletPassword as well when the host has no device share for the vault.

Reading vaults

getMultisigs lists a chain’s vaults, narrowed to one owner wallet when you pass walletAddress. getMultisigById returns a single vault.
getPaginatedMultisigs defaults to page: 1, limit: 10 and serializes chainTypes as a comma-separated query value (?chainTypes=EVM,SOL).
getMultisigById lower-cases EVM addresses before the lookup (the backend matches with LOWER()) and leaves base58 / mixed-case addresses on SOL, TRON, XRP, ADA, and BTC untouched, because lower-casing would corrupt them.

Rename and delete

createMultisig does not accept a name. Call updateMultisigName right after creating if you want one. deleteMultisig removes the vault from the account, not from the chain. Funds at the address remain reachable by anyone holding the owner keys.

Owner names

Each owner address can carry a display name. The address itself never changes.
  • Who sees what. Names set by the vault creator (at creation through ownerLabels, or later through setOwnerName) are the default every member sees. A name set by anyone else who can see the vault overrides the default for that caller only. owners[].label is already resolved for the caller; defaultLabel and customLabel show where it came from, and isCreator tells the caller which of the two its calls change.
  • Clearing. resetOwnerName removes the caller’s own name, so the default shows again. Called by the creator, it removes the default for everyone who has not set their own. With no name at all, show Address N, where N follows the order of owners.
  • Validation. The name is trimmed and must be 1–100 characters; otherwise InvalidInputError (Name must be 1–100 characters) is thrown before any request. Duplicate names are allowed.
  • Scope. On EVM a vault deployed on several chains has one record per chain; a name set through any of them applies to all. Vaults created before owner names existed have no recorded creator, so every name set on them is personal.
  • Recovery file. It uses the names as the downloading caller sees them. A file downloaded earlier keeps the names it had.

Changing owners and threshold

Owner and threshold changes are not a vault method. They are orders, created with createSettingsOrder and subject to the same signing threshold as a transfer:
newOwners is the complete desired final list, not a delta. The SDK diffs it against multisig.owners, diffs newThreshold against multisig.threshold, and picks the method with getChangeMethod: No detected change throws InvalidInputError: No changes detected in multisig configuration. To name the owners an order adds, call setOwnerName for each of them once the order is created. The address does not have to be an owner yet; the name shows once the order executes. XRP settings changes go through createOrder with the XRP instruction types (xrp_changeThreshold, xrp_updateOwners, xrp_updateOwnerThreshold). Bitcoin and Cardano have no settings orders at all. See Orders for the full lifecycle.

Transaction history

Both return TxHistoryCombinedResponse ({ items, total, page, limit }). getMultisigTxHistory defaults to page: 1, limit: 10; getAllMultisigsTxHistory defaults to limit: 20.

Organization vaults

Passing walletScope: 'organization' runs every vault lifecycle call against org-owned vaults instead of personal ones, with identical request and response shapes. A vault that is not yours surfaces as a 404 Vault not found; treat it as terminal and do not retry on the personal path. Organization vaults also have their own read methods (listOrgVaults, listMyOrgVaults, getOrgVaultById, getOrgVaultHistory). See Organization Vaults.

Next

Orders

Create, sign, and execute vault transactions.

Multisig Network Fees

Who pays what, at every step, on every chain.

Preflight

Simulate an order before a signature is collected.

Organization Vaults

Vaults owned by an organization rather than by one user.
Last modified on October 27, 2026