Every proof expires 10 minutes after it is issued
(
expires_at). A proof attests a moment in time; if a counterparty needs a
fresh one, create a new signature.The anti-phishing envelope
CBPay never signs a free-form message. Both flows build the same structured envelope, so the signer always sees what is being attested, which wallet signs it and until when it is valid:wallet_link purpose adds an Account: line with your masked account id.
A signature whose envelope is expired, not yet valid, or bound to a different
wallet is rejected.
1. Server-side signature (segregated wallet)
Sign with a segregated wallet custodied by CBPay (custody: cbpay). Because this flow produces a signature with a
custodied key, it requires KYC approved and an OTP challenge.
1
Create the OTP challenge
Ask for a one-time code for the
sign_message action and verify it to get
an X-OTP-Token (see OTP).2
Request the signature
purpose is wallet_ownership or treasury_attestation. statement is an
optional free-text line (max 140 runes) embedded in the envelope.201
3
Share the public link
Send
verify_url to the counterparty. They open it without credentials and
see the proof, its status and the signature.wallet_signature_created webhook.
List, detail and revoke
2. Link an external wallet (MetaMask / TronLink)
To prove ownership of a wallet you hold the keys to (not custodied by CBPay), complete a signed challenge:1
Create the challenge
201
2
Sign the envelope in the wallet
Show the
envelope text to the owner and ask them to sign it exactly as
shown with the wallet at address (MetaMask personal_sign for eth,
TronLink for tron). The challenge expires in 10 minutes.3
Submit the signature
200
purpose: wallet_link)
and fires the wallet_linked webhook. List and revoke links:
3. Public verification
Anyone with the link can verify a proof — no account, no token:200
valid is true only when the proof is signed, not revoked, not expired and
the signature still matches the envelope (verified_live re-checks the
cryptography on every call). An unknown or malformed code returns
404 not_found.
Status
Errors
Webhooks
Subscribe to these events (see Webhooks):wallet_signature_created
wallet_linked
FAQ
Does a signature proof move funds or cost gas?
Does a signature proof move funds or cost gas?
No. Signing a message is purely cryptographic: no on-chain transaction, no
network fee, no balance change.
How long is a proof valid?
How long is a proof valid?
10 minutes from
issued_at. After that the public link shows the proof as
expired. Create a new signature when a fresh attestation is needed.Can I revoke a proof?
Can I revoke a proof?
Yes —
POST /v1/signature-proofs/{proofID}/revoke. The public link keeps
working and reports status: revoked, so past verifications remain
auditable.Which wallets can sign in the wallet-link flow?
Which wallets can sign in the wallet-link flow?
Any wallet that supports
personal_sign on Ethereum (EIP-191) or message
signing on TRON (TIP-191) — MetaMask, TronLink and compatible wallets.Why was my statement rejected?
Why was my statement rejected?
The envelope accepts up to 140 runes of statement. Requests over 280
characters fail with
invalid_statement; between 141 and 280 the envelope
rejects them with sign_rejected.