Event catalog
Every event a Clav webhook can receive and the fields each one carries.
Naming convention
Events follow the format <resource>.<past-tense fact>, such as
wallet.verified. The resource comes first so you can handle a whole domain by
prefix. The verb is in the past tense because the event announces something that
already happened.
New events may be added without notice. Ignore the ones your endpoint does not
recognize and respond 2xx anyway, so they do not trigger needless retries.
Available events
| Event | When it is sent |
|---|---|
wallet.verified | A wallet proof was accepted. |
wallet.failed | A wallet proof was rejected or arrived after the deadline. |
Wallet events
Both wallet events share the same data shape. They are emitted by the wallet
verification product.
| Field | Type | Description |
|---|---|---|
organizationId | string | Organization that owns the challenge. |
challengeId | string | Challenge identifier. |
externalCustomerId | string | The customer identifier you sent when opening the challenge. |
chain | string | EVM, BITCOIN, TRON or SOLANA. |
address | string | Normalized address that had to be proved. |
method | string | SIGNATURE or MICRO_TRANSACTION. |
nonce | string | Unique challenge identifier, the same as in GET /v1/wallet-proofs/{nonce}. |
status | string | VERIFIED, FAILED or EXPIRED. |
recoveredAddress | string or null | Address that actually signed, when it could be recovered. |
failureReason | string or null | Why it failed. null on wallet.verified. |
verifiedAt | string or null | Verification time, in ISO-8601. |
verifiedWalletId | string or null | Verified wallet created or updated. null on wallet.failed. |
wallet.verified
{
"id": "65f0a1b2c3d4e5f60718293a-wallet.verified",
"event": "wallet.verified",
"occurredAt": "2026-09-16T12:04:11.000Z",
"data": {
"organizationId": "65e9f0a1b2c3d4e5f6071829",
"challengeId": "65f0a1b2c3d4e5f60718293a",
"externalCustomerId": "customer-8842",
"chain": "EVM",
"address": "0x5b38da6a701c568545dcfcb03fcb875f56beddc4",
"method": "SIGNATURE",
"nonce": "a3f1c0d9e8b7a6f5e4d3c2b1a0998877665544332211ffeeddccbbaa99887766",
"status": "VERIFIED",
"recoveredAddress": "0x5b38da6a701c568545dcfcb03fcb875f56beddc4",
"failureReason": null,
"verifiedAt": "2026-09-16T12:04:11.000Z",
"verifiedWalletId": "65f0a1b2c3d4e5f60718293b"
}
}wallet.failed
Sent when the signature is rejected or arrives after the deadline. Check
status to tell the two cases apart and failureReason for the cause. The list
of reasons is on the wallet verification
page. A challenge that lapses with no attempt at all sends no event.
{
"id": "65f0a1b2c3d4e5f60718293a-wallet.failed",
"event": "wallet.failed",
"occurredAt": "2026-09-16T12:04:11.000Z",
"data": {
"organizationId": "65e9f0a1b2c3d4e5f6071829",
"challengeId": "65f0a1b2c3d4e5f60718293a",
"externalCustomerId": "customer-8842",
"chain": "EVM",
"address": "0x5b38da6a701c568545dcfcb03fcb875f56beddc4",
"method": "SIGNATURE",
"nonce": "a3f1c0d9e8b7a6f5e4d3c2b1a0998877665544332211ffeeddccbbaa99887766",
"status": "FAILED",
"recoveredAddress": "0xab8483f64d9c6d1ecf9b849ae677dd3315835cb2",
"failureReason": "ADDRESS_MISMATCH",
"verifiedAt": null,
"verifiedWalletId": null
}
}Use the API to release withdrawals
Use the events to update your interface and your records. When releasing a
withdrawal, keep calling GET /v1/wallets, which also accounts for revocations
made after the proof.