Receiving Wallet
Link a receiving wallet by scanning a QR with the mobile app: start a link session and poll its status.
Start wallet link
https://api.gobtcpay.com/public/api/v1.2/merchant/wallet/link/startStarts a wallet-link session. Returns a one-time linkToken, the qrPayload to render as a QR code, and expiresAt. The user scans the QR with the GoBTC Pay mobile app to link their wallet; poll Wallet link status until it reports linked.
Authorization: merchantAuth
Responses
idstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6resultobjectrequiredcurl -X POST "$BASE_URL/merchant/wallet/link/start" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN"{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"result": {
"$case": "success",
"success": {
"linkToken": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImFjY2VzcyJ9.eyJwa2giOiIwMmExNjMzYyIsImNpZCI6IjNmYTg1ZjY0IiwiaWF0IjoxNzE4MDEyMzQ1fQ.MEQCIE3aGoQk0vY9c5kq",
"qrPayload": "bitcoin:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq?amount=0.0005",
"expiresAt": 1718012345
}
}
}Wallet link status
https://api.gobtcpay.com/public/api/v1.2/merchant/wallet/link/statusPolls a link session by linkToken (or the active merchant's current state when omitted). Returns status (pending / linked / expired) and the linked address once available.
Authorization: merchantAuth
Body required
application/jsonlinkTokenstringThe link token returned by Start wallet link to poll.
eyJhbGciOiJFUzI1NiIsImtpZCI6ImFjY2VzcyJ9.eyJwa2giOiIwMmExNjMzYyIsImNpZCI6IjNmYTg1ZjY0IiwiaWF0IjoxNzE4MDEyMzQ1fQ.MEQCIE3a…Responses
idstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6resultobjectrequiredcurl -X POST "$BASE_URL/merchant/wallet/link/status" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"linkToken": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImFjY2VzcyJ9.eyJwa2giOiIwMmExNjMzYyIsImNpZCI6IjNmYTg1ZjY0IiwiaWF0IjoxNzE4MDEyMzQ1fQ.MEQCIE3aGoQk0vY9c5kq"
}'{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"result": {
"$case": "success",
"success": {
"status": "pending",
"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
}
}
}Non-custodial balance
https://api.gobtcpay.com/public/api/v1.2/merchant/wallet/get-balanceThe non-custodial merchant's own money, split into three non-overlapping levels: connectedWalletSats (confirmed on the reserved 0/0 address), paymentWalletsSats (confirmed on the per-payment addresses of payments that are detected, paid or cleared) and inFlightSats (still unconfirmed in the mempool, and signed, negative means an outgoing spend not yet in a block).
All figures come from the chain, never from the payment ledger: the platform does not see the merchant's outgoing transactions, so a ledger-derived number would be total receipts rather than a balance. When the chain cannot be reached the last known values are returned with balanceStale: true, they are never substituted with an internally computed amount. addressesTruncated: true means the merchant holds funds on more addresses than one refresh may query, so the totals are incomplete and must be presented as such.
Custodial merchants are rejected: their funds sit on the platform treasury address, see Custodial balance.
Authorization: merchantAuth
Responses
idstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6resultobjectrequiredcurl -X POST "$BASE_URL/merchant/wallet/get-balance" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN"{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"result": {
"$case": "success",
"success": {
"connectedWalletSats": "string",
"paymentWalletsSats": "string",
"inFlightSats": "string",
"walletLinked": true,
"balanceAsOf": 1718012345,
"balanceStale": true,
"addressesTruncated": true,
"signedPsbtSats": "cHNidP8BAHECAAAAAfYI0kF1pQ0i3xL0AAAAAAD9////AsBdAQAAAAAAFgAUdR5"
}
}
}Wallets with a balance
https://api.gobtcpay.com/public/api/v1.2/merchant/wallet/listPaginated list of the non-custodial merchant's addresses that currently hold money, the connected 0/0 address and the per-payment addresses under observation. Each row carries address, kind (connected / payment), derivationPath, paymentId (null for the connected wallet), confirmedSats and inFlightSats. Addresses with a zero total are omitted. Custodial merchants are rejected, they have no addresses of their own.
Authorization: merchantAuth
Body required
application/jsonpaginationobjectResponses
idstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6resultobjectrequiredcurl -X POST "$BASE_URL/merchant/wallet/list" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"pagination": {
"limit": 20,
"skip": 0
}
}'{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"result": {
"$case": "success",
"success": {
"items": [
{
"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"kind": "connected",
"derivationPath": "string",
"paymentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"confirmedSats": "string",
"inFlightSats": "string"
}
],
"totalCount": 0
}
}
}Build withdrawal PSBT
https://api.gobtcpay.com/public/api/v1.2/merchant/wallet/build-withdraw-psbtBuilds an unsigned single-sig P2WPKH PSBT spending UTXOs of the merchant's own fromAddresses to toAddress. Exactly one of amountSats (leaves change on a connected merchant address) or sendMax (sweeps everything selected minus fee, no change) must be set. The server never signs, the merchant signs every input on their own device, then confirms with Broadcast withdrawal. The returned summary (including the change address) is a display convenience only; the client must verify every output against the PSBT itself before signing. The job is reserved as prepared the moment this call returns and expires after a server-side TTL if never broadcast. Custodial merchants are rejected, they have no addresses of their own.
Authorization: merchantAuth
Body required
application/jsonfromAddressesstring[]requiredtoAddressstringrequiredDestination Bitcoin address for the funds.
bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdqamountSatsstring | numberAmount in satoshis.
sendMaxbooleanIf true, sweeps the entire spendable balance to toAddress and ignores the amount.
truefeeobjectrequiredResponses
idstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6resultobjectrequiredcurl -X POST "$BASE_URL/merchant/wallet/build-withdraw-psbt" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"fromAddresses": [
"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
],
"toAddress": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"amountSats": "string",
"sendMax": true,
"fee": {
"feeRateSatVb": 50000
}
}'{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"result": {
"$case": "success",
"success": {
"jobId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"psbtBase64": "cHNidP8BAHECAAAAAfYI0kF1pQ0i3xL0AAAAAAD9////AsBdAQAAAAAAFgAUdR5",
"summary": {
"toAddress": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"amountSats": "string",
"feeSats": "string",
"feeRateSatVb": 50000,
"vsize": 140,
"change": {
"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"valueSats": "string"
},
"inputs": [
{
"txid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
"vout": 0,
"value": 50000,
"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"derivationPath": "string"
}
]
}
}
}
}Broadcast withdrawal
https://api.gobtcpay.com/public/api/v1.2/merchant/wallet/broadcastHands over the withdrawal transaction the merchant signed and finalized locally, as raw signedTxHex, for the server to validate against the stored job and broadcast. Idempotent by jobId: wasAlreadySubmitted: true means the transaction was already broadcast and the returned txid is the stored one, not a new attempt.
Authorization: merchantAuth
Body required
application/jsonjobIdstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6signedTxHexstringrequired0014751e76e8199196d454941c45d1b3a323f1433bd6Responses
idstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6resultobjectrequiredcurl -X POST "$BASE_URL/merchant/wallet/broadcast" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"jobId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"signedTxHex": "0014751e76e8199196d454941c45d1b3a323f1433bd6"
}'{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"result": {
"$case": "success",
"success": {
"txid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
"wasAlreadySubmitted": true
}
}
}Withdrawal job status
https://api.gobtcpay.com/public/api/v1.2/merchant/wallet/withdraw-statusReads the current state of a withdrawal job by jobId, prepared / broadcasting / broadcasted / expired / failed, the same set the job row carries. A pure read with no side effects, safe to poll repeatedly; it exists because Broadcast withdrawal is idempotent but not informative, retrying it resubmits the same stored hex, but a job that is already expired or failed makes it fail outright rather than report a state. After a broadcast error, or after the app restarts and loses whatever local state it had, this is the only way left to learn whether the money moved. txid is set once the network has one for this job and null before that; summary (amount, fee, destination, change) and expiresAt let the app show the withdrawal without keeping any of it around locally, expiresAt goes back to null once the job is past waiting on the reservation TTL. A jobId belonging to a different merchant is rejected as NotFound, identically to one that does not exist.
Authorization: merchantAuth
Body required
application/jsonjobIdstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6Responses
idstringrequired3fa85f64-5717-4562-b3fc-2c963f66afa6resultobjectrequiredcurl -X POST "$BASE_URL/merchant/wallet/withdraw-status" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"jobId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"result": {
"$case": "success",
"success": {
"status": "prepared",
"txid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
"expiresAt": 1718012345,
"summary": {
"toAddress": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"amountSats": "string",
"feeSats": "string",
"feeRateSatVb": 50000,
"change": {
"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"valueSats": "string"
}
}
}
}
}