Withdraw - Self-Custody Multisig (Manual)
Build, sign, and send withdrawals with granular control. See the Guide.
-
Build the transaction by specifying transaction details and sending them to BitGo. BitGo constructs an unsigned transaction that wallet co-signers can sign.
For UTXO assets in quick succession, reserve unspents by passing
reservationandexpireTimeparameters to avoid errors. -
Using the
txHexandtxInforeturned from Build Transaction, sign the transaction using your private key. BitGo Express is required for signing.For external signing-mode, use the Sign Wallet Transaction endpoint instead.
-
Send the half-signed transaction to BitGo. If approval is not required, BitGo applies the final signature and broadcasts to the blockchain. If you have policy rules requiring approvals, the transaction remains pending until approved.
-
If your withdrawal requires approval, another admin must approve it — you cannot approve your own transactions. Once approved, BitGo rebuilds the transaction with current fees, applies the final signature, and broadcasts to the blockchain.
// 1. Build Transaction
export COIN="<ASSET_ID>"
export WALLET_ID="<YOUR_WALLET_ID>"
export ACCESS_TOKEN="<YOUR_ACCESS_TOKEN>"
export ADDRESS="<DESTINATION_ADDRESS>"
export AMOUNT="<AMOUNT_IN_BASE_UNITS>"
curl -X POST \
https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/tx/build \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"recipients": [
{
"amount": "'"$AMOUNT"'",
"address": "'"$ADDRESS"'"
}
]
}'
// 2. Sign Transaction
export BITGO_EXPRESS_HOST="<YOUR_LOCAL_HOST>"
export PRV="<YOUR_PRIVATE_KEY>"
export USER_PUB="<YOUR_USER_PUBLIC_KEY>"
export BACKUP_PUB="<YOUR_BACKUP_PUBLIC_KEY>"
export BITGO_PUB="<BITGO_PUBLIC_KEY>"
curl -X POST \
http://$BITGO_EXPRESS_HOST/api/v2/$COIN/signtx \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"prv": "'"$PRV"'",
"pubs": ["'"$USER_PUB"'", "'"$BACKUP_PUB"'", "'"$BITGO_PUB"'"],
"txPrebuild": {
"wallet": "'"$WALLET_ID"'",
"txHex": "<TX_HEX_FROM_STEP_1>",
"txInfo": { },
"feeInfo": { },
"coin": "'"$COIN"'"
}
}'
// 3. Send Transaction
curl -X POST \
https://app.bitgo-test.com/api/v2/$COIN/wallet/$WALLET_ID/tx/send \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"halfSigned": {
"txHex": "<HALF_SIGNED_TX_HEX_FROM_STEP_2>"
}
}'
// 4. Approve Transaction (Optional)
export APPROVAL_ID="<APPROVAL_ID>"
export OTP="<YOUR_OTP>"
curl -X PUT \
https://app.bitgo-test.com/api/v2/pendingApprovals/$APPROVAL_ID \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"state": "approved",
"otp": "'"$OTP"'"
}'
// 1. Build Transaction
let buildParams = {
recipients: [
{
amount: `<AMOUNT>`,
address: `<DESTINATION_ADDRESS>`,
},
],
};
wallet.prebuildTransaction(buildParams).then(function (transaction) {
console.log(JSON.stringify(transaction, null, 2));
});
// 2. Sign Transaction
let signParams = {
txPrebuild: {
txHex: "<TX_HEX_FROM_STEP_1>",
txInfo: { },
feeInfo: { },
},
prv: `<YOUR_PRIVATE_KEY>`,
};
wallet.signTransaction(signParams).then(function (transaction) {
console.dir(transaction);
});
// 3. Send Transaction
let sendParams = {
txHex: '<HALF_SIGNED_TX_HEX_FROM_STEP_2>',
otp: '0000000',
};
wallet.submitTransaction(sendParams).then(function (transaction) {
console.dir(transaction);
});
// 4. Approve Transaction (Optional)
const baseCoin = bitgo.coin('<ASSET_ID>');
const pendingApproval = await baseCoin.pendingApprovals().get({ id: '<APPROVAL_ID>' });
const result = await pendingApproval.approve({ otp: '0000000' });
// 1. Build Transaction Response
{
"txHex": "01000000010e4d3af014f9efe311062965d561b67f78a1759e...",
"txInfo": {
"nP2SHInputs": 0,
"nSegwitInputs": 1,
"nOutputs": 2,
"unspents": [{ "chain": 10, "index": 5, "value": 100000 }],
"changeAddresses": ["tb1ps5xs4drx69wtz4ja655dfktsnulydaqag8lxm992qymcucnfswvspwdwxq"]
},
"feeInfo": {
"size": 226,
"fee": 20451,
"feeRate": 90491
},
"coin": "tbtc4"
}
// 2. Sign Transaction Response
{
"txHex": "010000000001010e4d3af014f9efe311062965d561b67f78a1759e..."
}
// 3. Send Transaction Response (approval not required)
{
"transfer": {
"id": "65528cde229f765c57a8f4d1eb762908",
"coin": "tbtc4",
"txid": "c68916ddc1672ec62c474ef0839ec479ad9b2dabc2249177ce6be6247f81dfe7",
"state": "signed",
"type": "send",
"value": -29987
},
"txid": "c68916ddc1672ec62c474ef0839ec479ad9b2dabc2249177ce6be6247f81dfe7",
"status": "signed"
}
// 3. Send Transaction Response (pending approval)
{
"error": "triggered all transactions policy",
"pendingApproval": {
"id": "65529448bd87efe59c3b0156ddfce867",
"state": "pendingApproval",
"approvalsRequired": 1
}
}
// 4. Approve Transaction Response
{
"id": "65529448bd87efe59c3b0156ddfce867",
"state": "approved",
"info": {
"transactionRequest": {
"validTransactionHash": "5ea8d2b93997ed9fa3597a2f3113817c8216f573a0278c2533bb5db50fdb0dff"
}
}
}