Wallet Verification Results and Attestations
Verification states, the verification and attestation objects, how to re-check a signature yourself, and the signed message format.
When a user signs, Wallet Verification checks the signature and stores an attestation on the verification. The attestation holds everything you need to re-check the proof independently.
Verification states
| State | Terminal | Meaning |
|---|---|---|
pending | No | Created. Waiting for the user to sign. |
verified | Yes | The signature checked out. attestation is set. |
failed | Yes | The signature did not verify. failure_reason is set. |
expired | Yes | expires_at passed without a signature. |
cancelled | Yes | You cancelled the verification. The link no longer works. |
failure_reason is currently always invalid_signature.
Verification object
| Field | Description |
|---|---|
id | Verification ID, ver_ followed by 32 hex characters. |
state | One of the states above. |
reference_id | Your identifier from create. |
purpose | withdrawal, payout, onboarding, or re_verification. |
chain_id | CAIP-2 chain ID you pinned, or null. |
expected_address | Address you pinned, or null. |
expires_at | When the link stops working. |
return_url | Return URL you set, or null. |
created_at | When the verification was created. |
metadata | Your metadata object, echoed back. Never signed. |
failure_reason | Set when state is failed. |
attestation | Set when state is verified. See below. |
The create response also includes url. No other response returns it.
Attestation object
| Field | Description |
|---|---|
address | Verified address. EIP-55 checksummed for EVM, base58 for Solana. |
chain_id | CAIP-2 chain ID the user signed on. |
message | The exact text the user signed. |
signature | 0x hex for EVM, base58 for Solana. |
wallet_type | eoa, eoa_7702, contract, or counterfactual. |
verification_method | ecrecover, erc1271, erc6492, or ed25519. |
block_number | Block the contract check ran at, as a decimal string. null for stateless methods. |
block_hash | Hash of that block. null for stateless methods. |
verified_at | When the signature was verified. |
ecrecover and ed25519 are stateless. erc1271 and erc6492 call the wallet contract, so they record the block.
Attestations are kept for 5 years.
Verify an attestation yourself
You can re-check any attestation without trusting Wallet Verification. Pick the check that matches verification_method.
These examples are illustrative. Use them as a starting point and adapt chain selection, RPC endpoints, and error handling to your stack.
Recover the EIP-191 personal_sign signer over message and compare it to address.
import { verifyMessage } from "viem";
const valid = await verifyMessage({
address: attestation.address,
message: attestation.message,
signature: attestation.signature,
});Signed message
EVM wallets sign an EIP-4361 (Sign-In with Ethereum) message. Solana wallets sign the equivalent CAIP-122 message.
{page host} wants you to sign in with your {Ethereum|Solana} account:
{address}
{Requester name} asks you to verify wallet ownership to {purpose text}.
URI: {page origin}/s
Version: 1
Chain ID: {EVM: chain number, e.g. 1 | Solana: full CAIP-2 id}
Nonce: {nonce}
Issued At: {created_at}
Expiration Time: {expires_at}
Request ID: {verification id, ver_…}| Purpose | Purpose text |
|---|---|
withdrawal | authorise a withdrawal to this wallet |
payout | receive payouts at this wallet |
onboarding | complete onboarding |
re_verification | re-confirm ownership of this wallet |
The requester name is the business name from Customization, with accents stripped to fit the format. Without one, it reads "The requester". Your reference_id and metadata are not part of the message.
To fetch only the signed text, call GET /verifications/{id}/message. It returns text/plain, or 409 not_verified if the verification is not verified.