Portal Community
These operations move real Bitcoin. Read this whole page — especially psbt/sign's fund-safety rule — before wiring this pipeline into a production workflow.

Why a Pipeline?

Bitcoin has no single-call "sign this transaction" primitive. The natural unit of work is a PSBT (Partially Signed Bitcoin Transaction, BIP-174) — a portable, base64-encoded artifact that passes through a multi-step pipeline, each step its own operation:

psbt/build     → unsigned PSBT (coin selection + fee calculation)
psbt/sign      → +1 signature (call once per required signature)
psbt/combine   → merges independently-signed copies (multisig only)
psbt/finalize  → final scriptSig/witness (re-validates every UTXO is still unspent)
psbt/extract   → raw transaction hex
transaction/broadcast → submits to the network

build

Creates an unsigned PSBT: selects UTXOs to cover the requested outputs plus fee, computes change, and serializes the result.

FieldTypeRequiredDescription
networkselect✓ YesFund-moving — must be explicit.
fromAddresstextConditionalAddress to spend from — the node fetches its UTXOs automatically. Required unless an explicit utxos[] list is supplied instead.
utxos[]arrayNoExplicit UTXOs to spend instead of auto-selecting: {txid, vout, valueSats, redeemScript?, address?}. address is required per-entry when it differs from fromAddress, or when fromAddress itself is omitted. Not needed for a P2WSH multisig UTXO — redeemScript alone determines its scriptPubKey.
outputs[]array✓ YesAt least one destination: {address, amountSats}.
changeAddresstextNoWhere leftover value returns. If omitted and change is generated, the build fails validation rather than silently picking an address.
feeRateSatVbdecimalNoSat/vB fee rate. If omitted, consults fee/getEstimates's fastest target automatically.
addressTypeselectNo (default p2wpkh)p2wpkh or p2tr.
enableRbfbooleanNo (default true)Signal Replace-By-Fee, allowing this transaction to be fee-bumped before confirmation.
locktimenumberNo (default 0)Transaction nLockTime.
reservationTimeoutSecondsnumberNoOverrides Bitcoin:UtxoReservation:LockTimeoutSeconds for this build — use a longer value for human-in-the-loop multisig approval flows.
idempotencyKeytextNoSafe-retry key for this build call.

Example response:

{
  "psbtBase64": "cHNidP8BAHECAAAAAd...",
  "inputsSelected": [ { "txid": "8f3c...", "vout": 0, "valueSats": 500000, "confirmed": true } ],
  "totalInputSats": 500000,
  "feeSats": 1400,
  "feeRateSatVb": 12.5,
  "changeSats": 88600,
  "changeAddress": "bc1q...",
  "expectedOutputsHash": "a94f...b21"
}
Carry changeAddress/changeSats forward. If changeSats > 0, include { "address": changeAddress, "amountSats": changeSats } as one of psbt/sign's expectedOutputs[] entries — see below.

sign

Adds one signature to the PSBT (call once per required signature — e.g. twice for a 2-of-3 multisig).

FieldTypeRequiredDescription
networkselect✓ YesFund-moving — must be explicit.
psbtBase64text✓ YesThe PSBT from psbt/build (or a prior sign/combine step).
walletTypeselect✓ Yeswif or mnemonicreadOnly cannot produce a signature.
credentialIDnumber✓ YesVault reference to the signing key/mnemonic.
addressTypeselectNo (default p2wpkh)p2wpkh or p2tr.
derivationPathtextNoOverrides the default SLIP-44 path (see Networks) when walletType is mnemonic.
expectedOutputs[]array✓ YesThe complete, exact set of outputs the PSBT must contain: {address, amountSats} per entry. See the fund-safety callout below.
Fund-safety rule — read this before your first send: expectedOutputs[] is required and must be an exact set match against the PSBT's real outputs — same count, every output's address and amount matching one expected entry exactly. Without this check, a signing operation would blindly sign whatever PSBT it was handed, with no verification it matches what was originally built or approved — a validly-signed transaction to a substituted destination is exactly as valid, and exactly as irreversible once confirmed, as one to the intended destination. If psbt/build produced a change output (changeSats > 0), its changeAddress/changeSats must be included in expectedOutputs[] — there is no implicit "leftover output" tolerance of any kind. A mismatch fails with PSBT_OUTPUT_MISMATCH.

Example response:

{
  "psbtBase64": "cHNidP8BAHECAAAAAd...",
  "signaturesAddedForInputs": [0]
}

combine

Merges two or more independently-signed copies of the same PSBT — only needed for out-of-band multisig where different signers each sign their own copy separately.

FieldTypeRequiredDescription
networkselect✓ YesFund-moving — must be explicit.
psbtBase64List[]array of text✓ YesAt least two signed PSBT copies to merge.

finalize

Produces the final scriptSig/witness for each input. Re-validates that every input UTXO is still unspent immediately before finalizing — Bitcoin consensus itself is the real safety net here, but this check distinguishes a genuine race/expired reservation from a call that already succeeded on a prior attempt whose response was lost.

FieldTypeRequiredDescription
networkselect✓ YesFund-moving — must be explicit.
psbtBase64text✓ YesThe fully-signed PSBT.

Example response:

{
  "psbtBase64": "cHNidP8BAHECAAAAAd...",
  "allInputsFinalized": true,
  "alreadyBroadcastTxid": null,
  "inputOutpoints": [ { "txid": "8f3c...", "vout": 0 } ]
}
Response FieldMeaning
alreadyBroadcastTxidSet when this exact call already succeeded on a prior attempt — treat as success, not a fresh finalize.
inputOutpointsLets the caller release the UTXO reservation early on success rather than waiting out the full reservation timeout.

An input whose UTXO was spent elsewhere between build and finalize fails with PSBT_UTXO_NO_LONGER_AVAILABLE — see Troubleshooting.

extract

Extracts the final raw transaction hex from a finalized PSBT — the direct input to transaction/broadcast.

FieldTypeRequiredDescription
networkselect✓ YesFund-moving — must be explicit.
psbtBase64text✓ YesThe finalized PSBT.

Example response:

{
  "rawTransactionHex": "02000000000101...",
  "txid": "8f3c...e21a"
}

buildTaprootScriptPathInput

Not fully implemented. NBitcoin's PSBTInput has no leaf-script/control-block fields the way it does for key-path Taproot, so this operation's actual mechanism needs a dedicated spike before it's safe to ship. It's implemented as a best-effort field-attach for the timelock-leaf case only; the script-multisig-leaf case fails fast with PSBT_TAPROOT_SPIKE_PENDING. Key-path Taproot (P2TR) signing via psbt/build/psbt/sign is fully implemented and unaffected — this limitation only applies to Taproot script-path spends. See Roadmap.
FieldTypeRequiredDescription
networkselect✓ YesFund-moving — must be explicit.
psbtBase64text✓ YesPSBT to attach the script-path input to.
inputIndexnumberNo (default 0)Which input to build.
leafTypeselectNo (default timelock)Only timelock has best-effort support today.

Full Pipeline at a Glance

StepOperationRoleNeeds a credential?
1psbt/buildCreator/Updater — coin selection, fee, changeNo
2psbt/signSigner — once per required signature✓ Yes
3psbt/combineCombiner — multisig onlyNo
4psbt/finalizeFinalizer — re-validates UTXOs, builds final witnessNo
5psbt/extractExtractor — raw hexNo
6transaction/broadcastSubmits to the networkNo

See Examples for a full worked send-Bitcoin workflow through this pipeline end to end.