Skip to content

Result ​

Every successful start / verify / complete returns a WalletVerification. Branch UI on status. The same customerId + address pair is reused - a verified pair short-circuits the next create.

On verified, persist verificationId, address, and verifiedAt on your backend (or rely on the webhook). The returned record is enough to update UI; treat the record and/or webhook as the source of truth for fulfillment.

Statuses ​

StatusTerminal?What to do
pendingnoKeep going / retry the current step (connect, sign, or Coinbase)
verifiedyesSuccess. Stop waiting
failedyesShow an error. Start a new verify() / startVerification()
expiredyesChallenge TTL (~15 minutes) exceeded. Start a new verification

An invalid signature does not move the record to failed. The call errors and status stays pending - call verify() again with the same customer / address / network to re-sign.

failed and expired need a new verification. Calling verify() / startVerification() again is enough - the server issues a new id.

For Coinbase redirect, ?status= on the landing URL is a hint. Always use the record returned by completeVerification().

WalletVerification ​

FieldMeaning
verificationIdServer id. Use it if you persist the run or read ?verificationId= after Coinbase redirect
statusWhere the run is: pending (keep going), verified (done), failed / expired (start a new one)
methodHow they proved control: 'signature' (wallet) or 'exchange_oauth' (Coinbase). 'satoshi' is reserved
networkChain family of address: 'evm', 'solana', or 'bitcoin'
addressAddress the user claimed to control
orderIdMerchant order reference, or null when omitted on create
verifiedAtISO timestamp once status is verified; otherwise null
challengePending proof payload, or null when the record is terminal
ts
if (verification.status === 'verified') {
  verification.verificationId
  verification.address
  verification.verifiedAt
}

challenge ​

Present while status is pending. null after the challenge is consumed or the TTL lapses.

FieldMeaning
messageExact string the wallet must sign (signature only). Sign this as returned
authorizationUrlCoinbase login URL (exchange_oauth only). Expires with the challenge
nonceServer nonce bound into the challenge
expiresAtWhen this challenge dies. After this, status becomes expired

You do not normally read challenge yourself. verify() signs message; openVerificationTab() / redirect use authorizationUrl.

Identity and reuse ​

customerId + address is the cache key. If that pair is already verified, the next verify() or startVerification() returns status: 'verified' and challenge: null. Show success and skip the wallet or Coinbase UI.

Webhooks ​

Pass webhookUrl on verify() / startVerification() only when you need to override the partner default. The webhook is server-to-server - the SDK does not deliver it to the page. Treat the returned WalletVerification (and your webhook) as the source of truth for fulfillment.