PSBT Workflows for Multisig: Coordinating Multiple Signers Without Trust
Practical guide to using PSBTs for multisig transaction coordination across hardware wallets, watch-only nodes, and air-gapped signers.
Spending from a multisig wallet means getting multiple independent parties to agree on the same transaction without ever sharing private keys. Before PSBTs (Partially Signed Bitcoin Transactions), this coordination was fragile: signers needed compatible software, identical transaction serialization, and often a live connection to each other. PSBTs, formalized in BIP 174, introduced a standard container format that any wallet can produce, any signer can process, and any coordinator can combine. The result is trustless multisig coordination across hardware wallets, air-gapped devices, and watch-only nodes.
What Problem Do PSBTs Solve?
A Bitcoin transaction requires valid signatures for every input before it can be broadcast. In a single-key setup, one wallet handles everything. In a multisig configuration, the keys live on separate devices, potentially in different physical locations. The challenge: how does each signer know exactly what they are signing, without trusting a coordinator to construct the transaction honestly?
PSBTs solve this by packaging the unsigned transaction together with all the metadata each signer needs: UTXO data for fee verification, redeem scripts for multisig validation, and BIP 32 derivation paths so hardware wallets can locate the correct keys. Each signer independently verifies the transaction on their trusted display, adds their signature, and returns the result. No signer needs to trust any other participant.
Anatomy of a PSBT
A PSBT is a binary container starting with the magic bytes 0x70736274FF (the ASCII string "psbt" followed by a separator byte). It contains three sections: a global map, one per-input map for each transaction input, and one per-output map for each output. Every section is a sequence of key-value pairs terminated by a null byte.
Global Map
In PSBT version 0, the global map contains the full unsigned transaction (with empty scriptSigs and witnesses). It may also include extended public keys ( xpubs) with their master fingerprints and derivation paths, allowing signers to identify which keys belong to them.
Per-Input Fields
Each input map carries the data signers need to verify what they are spending and to produce valid signatures.
| Field | Purpose | When Required |
|---|---|---|
| Non-Witness UTXO | Full previous transaction, so signers can verify the TXID and amount being spent | Legacy (non-SegWit) inputs |
| Witness UTXO | Just the spent output (amount + scriptPubKey), sufficient for SegWit inputs | SegWit inputs |
| Partial Signature | A DER-encoded ECDSA signature keyed by the signer's compressed public key | Added by each signer |
| Redeem Script | The P2SH redeem script containing the multisig policy | P2SH and P2SH-P2WSH multisig |
| Witness Script | The P2WSH witness script (the actual multisig program) | P2WSH and P2SH-P2WSH multisig |
| BIP 32 Derivation | Maps each public key to its master fingerprint and derivation path | When hardware wallets need to locate signing keys |
| Sighash Type | Specifies which parts of the transaction are covered by the sighash flag | When non-default sighash is needed |
Per-Output Fields
Output maps include redeem scripts, witness scripts, and BIP 32 derivation data for change outputs. These let wallets verify that change is returning to an address they control, preventing a malicious coordinator from redirecting funds.
Why Witness UTXO matters for hardware wallets: Without the spent output's amount, a signing device cannot calculate the transaction fee. An attacker could craft a PSBT that overpays fees by millions of satoshis. BIP 174 requires either the full previous transaction (non-witness UTXO) or the witness UTXO so signers can independently verify the fee before approving.
The Six Roles in a PSBT Workflow
BIP 174 defines six distinct roles that can be performed by different software or devices. In practice, some roles are combined (a coordinator wallet often acts as Creator, Updater, Combiner, and Extractor), but the separation matters for security: the signing role is isolated on trusted hardware.
- Creator: constructs an empty PSBT with the unsigned transaction template (inputs, outputs, locktime)
- Updater: enriches the PSBT with UTXO data, redeem/witness scripts, and BIP 32 derivation paths for all cosigner keys
- Signer: examines each input, locates the matching private key, verifies the transaction on a trusted display, and adds a partial signature
- Combiner: merges multiple PSBTs for the same transaction into one, collecting all partial signatures
- Finalizer: when enough signatures exist, assembles the complete scriptSig and/or witness data and strips intermediate metadata
- Extractor: produces the fully serialized network transaction, ready for broadcast
Walkthrough: 2-of-3 Multisig with PSBTs
Consider a treasury setup with three signing devices: a Coldcard held by the CFO, a Foundation Passport stored in a safe deposit box, and a Trezor kept by an operations lead. A watch-only wallet running Sparrow on a networked laptop acts as the coordinator. Any two of three signers can authorize a spend.
Step 1: Wallet Setup
Each hardware wallet exports its extended public key (xpub) via USB, QR code, or SD card. The coordinator imports all three xpubs and constructs an output descriptor:
wsh(sortedmulti(2, [fingerprint_A/48h/0h/0h/2h]xpub_A/*, [fingerprint_B/48h/0h/0h/2h]xpub_B/*, [fingerprint_C/48h/0h/0h/2h]xpub_C/*))
The sortedmulti function (BIP 67) ensures deterministic key ordering so all participants derive identical addresses regardless of the order they import keys. The wsh() wrapper produces native P2WSH addresses, which have lower fees than P2SH-wrapped alternatives. The coordinator's wallet is watch-only: it has no private keys and cannot sign.
Step 2: Create the PSBT
When the organization needs to make a payment, the coordinator builds the transaction. Using bitcoin-cli:
bitcoin-cli -rpcwallet="treasury_watch" walletcreatefundedpsbt '[]' '[{"bc1q...destination": 0.5}]'
This command selects UTXOs, adds a change output, populates all input metadata (witness UTXOs, witness scripts, BIP 32 derivation paths for all three cosigner keys), and returns a base64-encoded PSBT. The coordinator saves this as a .psbt file.
Step 3: Distribute to Signers
The coordinator sends the unsigned PSBT to the CFO and the operations lead. Transport options depend on the signing device:
- Coldcard: copy the
.psbtfile to a MicroSD card and physically hand it over - Trezor: connect via USB to Sparrow and sign directly
- Keystone or SeedSigner: display as animated QR code for the device camera to scan
The signers do not need to communicate with each other. Each independently receives the same unsigned PSBT.
Step 4: Sign
Each signing device parses the PSBT, extracts the transaction details, and displays them on its trusted screen: destination address, amount, fee, and change output. The signer verifies these details match the intended payment, then approves. The device locates its private key using the BIP 32 derivation path embedded in the PSBT, produces a partial signature, and writes it into the PSBT's PSBT_IN_PARTIAL_SIG field keyed by the signer's compressed public key.
For a Coldcard using an SD card, the device writes a new file with -signed appended to the filename. The original unsigned file is not overwritten.
Step 5: Combine, Finalize, Broadcast
The coordinator collects both signed PSBTs and merges them:
bitcoin-cli combinepsbt '["psbt_from_cfo", "psbt_from_ops"]'
The Combiner merges all partial signatures into a single PSBT. The Finalizer then assembles the witness stack (the two signatures plus the witness script) and strips intermediate metadata:
bitcoin-cli finalizepsbt <combined_psbt>
If successful, this returns {"hex": "...", "complete": true}. The coordinator broadcasts the raw transaction with sendrawtransaction.
Sequential vs parallel signing: The workflow above uses parallel signing: both signers receive the original unsigned PSBT independently. Alternatively, signers can work sequentially: the CFO signs first and passes the partially signed PSBT to the operations lead, who adds the second signature. Sequential signing skips the combine step since the second signer's wallet appends its signature to the existing one. Both approaches produce identical final transactions.
PSBT Version 0 vs Version 2
BIP 370 introduced PSBT version 2 to address a fundamental limitation of v0: the unsigned transaction is locked at creation time. Once the Creator sets the inputs and outputs, no participant can modify them. This blocks interactive protocols like PayJoin and CoinJoin, where participants contribute inputs during construction.
| Aspect | PSBT v0 (BIP 174) | PSBT v2 (BIP 370) |
|---|---|---|
| Global transaction | Full unsigned transaction stored in the global map | No global transaction: data distributed across input/output maps |
| Input/output modification | Fixed at creation | Modifiable until the Constructor clears the modifiable flags |
| New role | N/A | Constructor: adds inputs/outputs before signing begins |
| Per-input fields | UTXO data, scripts, derivations, partial signatures | Same, plus PREVIOUS_TXID, OUTPUT_INDEX, SEQUENCE, and locktime requirements |
| Per-output fields | Scripts and derivations only | Same, plus AMOUNT and SCRIPT (formerly in the global tx) |
| Interoperability | Universal: supported by all PSBT-aware software | Growing adoption: Coldcard, Ledger Bitcoin app, Sparrow, BDK |
| Conversion | Cannot convert to v2 | Can downconvert to v0 by reconstructing the unsigned tx |
For standard multisig workflows, PSBT v0 remains the practical choice: it has universal support and the fixed transaction structure is not a limitation when all inputs and outputs are known upfront. Version 2 becomes necessary for interactive construction protocols and is required by BIP 375 for sending to silent payment addresses.
Taproot PSBTs and BIP 371
Taproot introduced Schnorr signatures and script trees, which required new PSBT fields defined in BIP 371. For key-path spends, signers produce a single 64-byte Schnorr signature stored in PSBT_IN_TAP_KEY_SIG. For script-path spends (used in Taproot-based multisig), each signer adds a PSBT_IN_TAP_SCRIPT_SIG entry keyed by their X-only public key and the relevant leaf hash. Additional fields carry the internal key, Merkle root, leaf scripts, and Taproot-specific BIP 32 derivation data.
Air-Gapped Signing Methods
Air-gapped signing eliminates all electronic communication between the signing device and any networked system. PSBTs are uniquely suited for air-gapped workflows because the format is self-contained: the signer receives everything needed to verify and sign without querying a node.
MicroSD Card
The coordinator writes the .psbt file to a FAT32 MicroSD card. The signer physically inserts the card into the hardware wallet, reviews the transaction on the device display, approves, and the device writes a signed .psbt file back to the card. The card is then returned to the coordinator. This method has no size limitations and works with complex transactions containing many inputs. Coldcard and Foundation Passport both support this workflow.
Animated QR Codes
For devices with cameras (SeedSigner, Keystone, Blockstream Jade), the PSBT is encoded as a sequence of animated QR frames. Two competing standards exist:
- UR (Uniform Resources) by Blockchain Commons: uses fountain codes for error recovery, with the
ur:psbttype tag. Frames can be captured in any order. Adopted by Sparrow, Keystone, Foundation Passport, and others - BBQr (Better Bitcoin QR) by Coinkite: uses Base32 encoding optimized for QR alphanumeric mode, with optional Zlib compression reducing payload by roughly 30%. Supports payloads up to 3.5 MB across 1,295 frames. Adopted by Coldcard Q
NFC
Near-field communication enables tap-to-sign workflows at a distance of under 4 cm. The unsigned PSBT is transferred on the first tap; the signed result returns on the second tap. NFC is practical for simple transactions (PSBTs under roughly 8 KB), but multisig transactions with multiple inputs may exceed this limit. Coldcard Mk5 and Q support NFC, though it is disabled by default.
PSBT Coordination Tools
Sparrow Wallet
Sparrow is a desktop Bitcoin wallet designed around descriptors and PSBTs. It serves as a full PSBT coordinator: creating transactions, exporting to hardware wallets via USB/QR/file, importing signed PSBTs, combining signatures, and broadcasting. Sparrow supports mixing hardware wallets from different manufacturers in a single multisig setup and provides a visual PSBT inspector showing all fields, signatures, and fee data. It connects to Bitcoin Core, Electrum servers, or public servers (with optional Tor).
Caravan
Caravan is an open-source, stateless multisig coordination tool originally built by Unchained Capital. It runs entirely in the browser with no backend: all transaction construction, PSBT creation, and signature combination happen client-side. Caravan supports Trezor, Ledger, Coldcard, and manual key import, with BCURv2 animated QR support for fully air-gapped signing. Because Caravan is stateless, users must externally back up their multisig configuration (xpubs, derivation paths, and the descriptor).
Bitcoin Core CLI
Bitcoin Core provides the full set of PSBT commands for scripting and automation. The key commands map directly to PSBT roles:
| Command | PSBT Roles | Description |
|---|---|---|
walletcreatefundedpsbt | Creator + Updater | Selects UTXOs, creates the PSBT, and populates all metadata |
walletprocesspsbt | Updater + Signer | Adds missing metadata and signs with available wallet keys |
descriptorprocesspsbt | Updater + Signer | Signs using provided descriptors without requiring a wallet (added in Bitcoin Core 25.0) |
combinepsbt | Combiner | Merges multiple signed PSBTs for the same transaction |
finalizepsbt | Finalizer + Extractor | Constructs final witness data and returns the raw transaction |
decodepsbt | Diagnostic | Outputs a human-readable JSON dump of all PSBT fields |
analyzepsbt | Diagnostic | Reports per-input status, estimated fees, and the next required role |
Programmatic PSBT Libraries
Developers building multisig coordination software can choose from mature libraries across multiple languages.
- bitcoinjs-lib (JavaScript/TypeScript): the
Psbtclass provides full lifecycle support includingaddInput,signInput,combine,finalizeAllInputs, andextractTransaction. It supports HD signing viasignInputHDand Taproot viasignTaprootInput - rust-bitcoin (Rust): the
bitcoin::psbtmodule implements BIP 174, with a separatepsbt-v2crate for BIP 370. Integrates with rust-miniscript for policy-based spending - BDK (Bitcoin Dev Kit): a higher-level wallet library built on rust-bitcoin that handles coin selection, fee estimation, and descriptor-based key management automatically. Available in Rust with bindings for Swift, Kotlin/JVM, Python, and WASM
- python-bitcointx: a Python library with a
PartiallySignedTransactionclass supporting PSBT creation and signing
For a comparison of wallet development frameworks, see the Bitcoin wallet SDK comparison.
Security Considerations
Fee Verification
The most critical security property of PSBTs is enabling signers to independently verify the transaction fee. Without UTXO data, a signer cannot calculate the difference between total input value and total output value. BIP 174 mandates that Updaters include either the full previous transaction (for legacy inputs) or the witness UTXO (for SegWit inputs) so signers can perform this check. Hardware wallets should reject PSBTs that lack this data.
Change Output Verification
A malicious coordinator could construct a PSBT where the change address is controlled by the attacker instead of the multisig quorum. The BIP 32 derivation paths in the output map let hardware wallets verify that change outputs belong to the same descriptor as the inputs. Signers should confirm on their device display that the change output is flagged as "internal" or "change."
Address Display Attacks
Hardware wallet attack vectors include compromised coordinator software that displays a different destination address than the one in the PSBT. Signers must always verify the destination address on the hardware wallet's own display, never on the coordinator's screen.
Defense in depth: PSBTs do not eliminate the need to verify transactions on trusted hardware. They ensure signers have the data to verify, but the human must still check the destination address, amount, and fee on the signing device's display before approving.
From Multisig PSBTs to Threshold Signatures
PSBT-based multisig coordination works, but it has inherent costs. Every input in a 2-of-3 multisig transaction carries two 72-byte DER signatures plus the witness script containing all three public keys. This consumes more block space than single-sig transactions, which translates directly to higher fees. The multisig structure is also visible on-chain: anyone analyzing the blockchain can identify multisig spends and infer the quorum policy.
FROST (Flexible Round-Optimized Schnorr Threshold signatures) takes a different approach. FROST threshold signatures allow a group of signers to collaboratively produce a single Schnorr signature that is indistinguishable from a regular single-key signature on-chain. The signing coordination still happens off-chain across multiple devices, but the result is a compact key-path spend that reveals nothing about the underlying threshold structure.
Spark uses FROST at its core: the user and the Spark operators collectively hold a threshold key, and transfers require collaborative signing without any party having complete key material. The coordination challenge is similar to PSBT multisig, but solved at the protocol layer rather than at the transaction format layer. For developers building on Spark, the Spark SDK handles threshold signing coordination automatically, without requiring manual PSBT construction.
When to Use PSBTs vs Alternatives
PSBTs are the right tool when you need on-chain multisig coordination with hardware wallet isolation. For other scenarios, alternatives may be more appropriate:
| Scenario | Best Approach | Why |
|---|---|---|
| Treasury cold storage (2-of-3, 3-of-5) | PSBT multisig | Maximum security with air-gapped hardware wallets, on-chain enforcement |
| Frequent payments with shared control | MuSig2 or FROST | Lower fees, better privacy, single on-chain signature |
| Instant transfers with self-custody | Spark | Off-chain settlement with threshold security, no on-chain footprint per transfer |
| Collaborative transaction building (PayJoin, CoinJoin) | PSBT v2 | Modifiable inputs/outputs allow interactive construction |
| Programmatic spending policies | Miniscript + PSBT | Policies expressed as descriptors, automated PSBT construction and signing |
Getting Started
For teams setting up their first multisig workflow, start with Sparrow and two hardware wallets from different manufacturers. Create a 2-of-3 on testnet (or signet) first to practice the full cycle: wallet creation, PSBT export, signing on each device, combination, and broadcast. Graduate to mainnet only after the workflow feels routine and every team member can independently verify transactions on their device.
For developers integrating PSBT workflows into applications, the wallet SDK comparison covers library options across languages. BDK is the most batteries-included choice for Rust-based projects, while bitcoinjs-lib remains the standard for JavaScript/TypeScript.
For those exploring off-chain alternatives to on-chain multisig, Spark's documentation covers how FROST-based threshold signing achieves similar multi-party security without the on-chain overhead.
This article is for educational purposes only. It does not constitute financial or investment advice. Bitcoin and Layer 2 protocols involve technical and financial risk. Always do your own research and understand the tradeoffs before using any protocol.

