RecipesWallets
Wallet Onboarding Workflow
How to create and configure wallets in Blockstream Enterprise Custody, from signer creation through address generation.
Complete Setup and Installation first.
This guide assumes:
- an authenticated user that can create signers and wallets
- the request helper from Making Requests
uuidfor the example IDs
Why signers are separate from wallets
The platform separates key custody from wallet configuration on purpose.
- A signer owns or references key material
- A wallet defines how those signers are used on-chain
- A wallet can reference one or more signers depending on its type
That separation makes several things easier:
- signer rotation without redesigning the wallet model
- clearer audits of who controls which signing path
- multi-signer wallet construction from independently managed signers
- reuse of the same signer in more than one wallet context
Standards context
Relevant external references:
- BIP-32: hierarchical deterministic key derivation
- BIP-39: mnemonic seed phrases
- BIP-87: descriptor-oriented derivation conventions
Wallet onboarding flow
Every wallet flow follows the same high-level sequence:
- create a signer
- derive an XPUB
- create the wallet
- generate addresses
Step 1: Create a signer
import { v4 as uuidv4 } from 'uuid'
const signerResult = await broadcastRequest({
action: 'add',
resource: '/signers',
details: {
sid: uuidv4(),
name: 'ops-signer',
location: 'hosted',
},
})
const signerId = signerResult.details.sidSigner locations
| Location | Meaning |
|---|---|
hosted | Keys are managed by the Custody Engine |
external | Keys are managed elsewhere |
If your environment does not yet support external signers in production, stay with hosted.
Step 2: Derive an XPUB
const xpubResult = await broadcastRequest({
action: 'add',
resource: `/signers/${signerId}/xpubs`,
details: {
id: uuidv4(),
change: 'receive',
},
})
const keyoriginXpub = xpubResult.details.keyorigin_xpubXPUB derivation matters because it lets the wallet generate receive and change addresses without exposing private signing material.
Step 3: Create the wallet
const walletResult = await broadcastRequest({
action: 'add',
resource: '/wallets',
details: {
id: uuidv4(),
name: 'treasury-wallet',
type: 'single_sig',
network: 'bitcoin',
value: { signer_id: signerId },
},
})
const walletId = walletResult.details.widStep 4: Generate an address
const addressResult = await broadcastRequest({
action: 'add',
resource: `/wallets/${walletId}/addresses`,
details: {
type: 'receive',
index: 1,
},
})
const address = addressResult.details.addressChoosing the right wallet flow
- Wallet Types for choosing the right wallet model
- Wallet Setup Prerequisites for signer and XPUB detail
- AMP Wallet for Liquid tokenization wallets