Custodial Withdrawal

Custodial merchants only: manage saved BTC destination wallets and withdraw the Uphold balance to them, including the Uphold Travel Rule verification a held withdrawal may require.

Add destination wallet

POSThttps://api.gobtcpay.com/public/api/v1.2/merchant/custodial/wallet/create

Custodial merchants only. Saves a BTC wallet the merchant can later withdraw to. Takes the address, an optional label, and a totpCode, adding a destination is a sensitive action and is gated by the merchant's TOTP. Returns the saved wallet: its id, merchantId, address, label, network, and createdAt. There is no asset field, a custodial merchant only ever holds bitcoin.

Authorization: merchantAuth

Body required

application/json
addressstringrequired
Example:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq
labelstring

Human-readable label for the POS terminal (optional).

Example:Front desk
totpCodestringrequired
Example:string

Responses

idstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
resultobjectrequired
POST /merchant/custodial/wallet/create
cURL
curl -X POST "$BASE_URL/merchant/custodial/wallet/create" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
  "address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
  "label": "Front desk",
  "totpCode": "string"
}'
200 Successful response
JSON
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "result": {
    "$case": "success",
    "success": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "merchantId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
      "label": "Front desk",
      "network": "string",
      "createdAt": 1718012345
    }
  }
}

List destination wallets

POSThttps://api.gobtcpay.com/public/api/v1.2/merchant/custodial/wallet/list

Custodial merchants only. Returns the merchant's saved BTC destination wallets as items, each with its id, merchantId, address, label, network, and createdAt. Takes no parameters, the merchant comes from the auth context.

Authorization: merchantAuth

Responses

idstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
resultobjectrequired
POST /merchant/custodial/wallet/list
cURL
curl -X POST "$BASE_URL/merchant/custodial/wallet/list" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
200 Successful response
JSON
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "result": {
    "$case": "success",
    "success": {
      "items": [
        {
          "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "merchantId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
          "label": "Front desk",
          "network": "string",
          "createdAt": 1718012345
        }
      ]
    }
  }
}

Create withdrawal

POSThttps://api.gobtcpay.com/public/api/v1.2/merchant/custodial/withdraw/create

Custodial merchants only. Starts a withdrawal of amountSats (before fees, in satoshi) from the merchant's Uphold balance to a saved wallet (walletId), gated by totpCode. Returns the created withdrawal with the quote it was accepted under in feeSummary (amountSats, feeSats, receivedSats and Uphold's feeBreakdown line items, all in satoshi). status is pending, or awaiting_travel_rule when Uphold requires Travel Rule information first. Typed failures include insufficient_available_balance, amount_below_minimum, pending_withdrawal_exists, fee_exceeds_amount, wallet_not_found, the address checks (address_validation_failed, address_wrong_network, address_not_btc), the TOTP checks (totp_required, totp_invalid, totp_not_configured), and the eligibility checks (not_custodial_merchant, no_uphold_account, withdraw_not_configured).

Authorization: merchantAuth

Body required

application/json
walletIdstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
amountSatsstring | numberrequired

Amount in satoshis.

totpCodestringrequired
Example:string

Responses

idstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
resultobjectrequired
POST /merchant/custodial/withdraw/create
cURL
curl -X POST "$BASE_URL/merchant/custodial/withdraw/create" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
  "walletId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "amountSats": "string",
  "totpCode": "string"
}'
200 Successful response
JSON
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "result": {
    "$case": "success",
    "success": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "status": "pending",
      "walletId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
      "walletLabel": "Front desk",
      "network": "string",
      "amountSats": "string",
      "feeSummary": {
        "amountSats": "string",
        "feeSats": "string",
        "receivedSats": "string",
        "feeBreakdown": [
          {
            "type": "withdraw",
            "code": "string",
            "asset": "string",
            "amount": null,
            "percentage": 0
          }
        ]
      },
      "travelRuleRequired": true,
      "createdAt": 1718012345
    }
  }
}

List withdrawals

POSThttps://api.gobtcpay.com/public/api/v1.2/merchant/custodial/withdraw/list

Custodial merchants only. Returns the merchant's withdrawals, newest first, as items with a totalCount. Every filter is optional: status narrows to one lifecycle state, from / to bound the creation time (inclusive unix seconds), and limit / skip page the result.

Authorization: merchantAuth

Body required

application/json
statusenum

Current status. Payments: initiated / detected / paid / failed / expired / canceled / cleared. Payment transactions: success / failed / pending / cleared.

pendingawaiting_travel_rulesubmittingprocessingon_holdcompletedfailedcanceled
Example:pending
frominteger

UnixTime (seconds since epoch)

Example:1718012345
tointeger

UnixTime (seconds since epoch)

Example:1718012345
limitinteger
Example:20
skipinteger
Example:0

Responses

idstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
resultobjectrequired
POST /merchant/custodial/withdraw/list
cURL
curl -X POST "$BASE_URL/merchant/custodial/withdraw/list" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
  "status": "pending",
  "from": 1718012345,
  "to": 1718012345,
  "limit": 20,
  "skip": 0
}'
200 Successful response
JSON
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "result": {
    "$case": "success",
    "success": {
      "items": [
        {
          "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "status": "pending",
          "walletId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "amountSats": "string",
          "quotedFeeSats": null,
          "quotedReceivedSats": null,
          "feeSats": null,
          "receivedSats": null,
          "feeBreakdown": [],
          "address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
          "walletLabel": "Front desk",
          "network": "string",
          "onchainTxid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
          "failureReason": "insufficient_balance",
          "travelRuleRequired": true,
          "createdAt": 1718012345,
          "submittedAt": 1718012345,
          "completedAt": 1718012345
        }
      ],
      "totalCount": 0
    }
  }
}

Get withdrawal

POSThttps://api.gobtcpay.com/public/api/v1.2/merchant/custodial/withdraw/get

Custodial merchants only. Fetches one withdrawal by withdrawalId. The withdrawal must belong to the authenticated merchant. Returns the full withdrawal item, including its quote (quotedFeeSats, quotedReceivedSats), the actual fee once settled (feeSats, receivedSats, feeBreakdown, null until then), onchainTxid, and the lifecycle timestamps.

Authorization: merchantAuth

Body required

application/json
withdrawalIdstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6

Responses

idstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
resultobjectrequired
POST /merchant/custodial/withdraw/get
cURL
curl -X POST "$BASE_URL/merchant/custodial/withdraw/get" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
  "withdrawalId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
200 Successful response
JSON
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "result": {
    "$case": "success",
    "success": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "status": "pending",
      "walletId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "amountSats": "string",
      "quotedFeeSats": "string",
      "quotedReceivedSats": "string",
      "feeSats": "string",
      "receivedSats": "string",
      "feeBreakdown": [
        {
          "type": "withdraw",
          "code": "string",
          "asset": "string",
          "amount": null,
          "percentage": 0
        }
      ],
      "address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
      "walletLabel": "Front desk",
      "network": "string",
      "onchainTxid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
      "failureReason": "insufficient_balance",
      "travelRuleRequired": true,
      "createdAt": 1718012345,
      "submittedAt": 1718012345,
      "completedAt": 1718012345
    }
  }
}

Cancel withdrawal

POSThttps://api.gobtcpay.com/public/api/v1.2/merchant/custodial/withdraw/cancel

Custodial merchants only. Cancels a withdrawal that has not been handed to Uphold yet, releasing the reserved funds and moving it to canceled. Returns { ok: true }, the outcome is single-valued, so a failure arrives as a typed error rather than as a withdrawal in another state. An already submitted withdrawal returns withdrawal_already_submitted, and one past submission returns withdrawal_not_cancellable.

Authorization: merchantAuth

Body required

application/json
withdrawalIdstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6

Responses

idstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
resultobjectrequired
POST /merchant/custodial/withdraw/cancel
cURL
curl -X POST "$BASE_URL/merchant/custodial/withdraw/cancel" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
  "withdrawalId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
200 Successful response
JSON
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "result": {
    "$case": "success",
    "success": {
      "ok": true
    }
  }
}

Open Travel Rule session

POSThttps://api.gobtcpay.com/public/api/v1.2/merchant/custodial/withdraw/travel-rule/session

Custodial merchants only. Opens an Uphold Travel Rule verification session for a withdrawal Uphold is holding (awaiting_travel_rule). Returns what Uphold's embedded widget needs to mount, relayed verbatim: flow, the widget url, a short-lived token, and provider-specific data. Safe to call repeatedly, nothing about the session is stored, and an expired one is replaced by asking again.

Authorization: merchantAuth

Body required

application/json
withdrawalIdstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6

Responses

idstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
resultobjectrequired
POST /merchant/custodial/withdraw/travel-rule/session
cURL
curl -X POST "$BASE_URL/merchant/custodial/withdraw/travel-rule/session" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
  "withdrawalId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}'
200 Successful response
JSON
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "result": {
    "$case": "success",
    "success": {
      "flow": "withdrawal-form",
      "url": "string",
      "token": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImFjY2VzcyJ9.eyJwa2giOiIwMmExNjMzYyIsImNpZCI6IjNmYTg1ZjY0IiwiaWF0IjoxNzE4MDEyMzQ1fQ.MEQCIE3aGoQk0vY9c5kq",
      "data": "string"
    }
  }
}

Submit Travel Rule info

POSThttps://api.gobtcpay.com/public/api/v1.2/merchant/custodial/withdraw/travel-rule/submit

Custodial merchants only. Submits the Travel Rule information the merchant completed in Uphold's widget for a held withdrawal. payload is the widget's complete result whole, including its nested value, Uphold requires the envelope intact, so it is required and forwarded verbatim; its inner shape is Uphold's. On success the withdrawal leaves awaiting_travel_rule and returns to pending for re-evaluation, which is the item returned.

Authorization: merchantAuth

Body required

application/json
withdrawalIdstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
payloadobjectrequired
Example:string

Responses

idstringrequired
Example:3fa85f64-5717-4562-b3fc-2c963f66afa6
resultobjectrequired
POST /merchant/custodial/withdraw/travel-rule/submit
cURL
curl -X POST "$BASE_URL/merchant/custodial/withdraw/travel-rule/submit" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
  "withdrawalId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "payload": "string"
}'
200 Successful response
JSON
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "result": {
    "$case": "success",
    "success": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "status": "pending",
      "walletId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "amountSats": "string",
      "quotedFeeSats": "string",
      "quotedReceivedSats": "string",
      "feeSats": "string",
      "receivedSats": "string",
      "feeBreakdown": [
        {
          "type": "withdraw",
          "code": "string",
          "asset": "string",
          "amount": null,
          "percentage": 0
        }
      ],
      "address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
      "walletLabel": "Front desk",
      "network": "string",
      "onchainTxid": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
      "failureReason": "insufficient_balance",
      "travelRuleRequired": true,
      "createdAt": 1718012345,
      "submittedAt": 1718012345,
      "completedAt": 1718012345
    }
  }
}