Wallet verification API
Check any VerifiedWallet certificate for free, or verify your own customers' wallets from your product: proof of ownership by signature on 15+ chains, with identity, AML screening, company checks and multisig on top. Results are signed, so you can check them without trusting us.
Two APIs
- Free check API: no key. Look up a wallet in the public register, fetch a certificate, check our signature, embed a badge. Open to any website.
- Verify API: with a key. Send your customer to our signing page; get a signed result back by webhook and API. Billed per verification, monthly. Typical uses: Travel Rule checks on self-hosted wallets, withdrawals to new addresses, OTC settlement, payroll and payouts, company treasury wallets.
Want keys? Tell us about your product and we'll set up an account with test and live keys. Or try it live below, right now.
Free check API
JSON over HTTPS, open to every origin (CORS), no key. Please be reasonable with volume.
GET /api/verify/<wallet address or certificate ID>: certificates in the public register for that wallet.GET /api/cert/<certificate ID>: one certificate, with its signedcoreand ourattestation.GET /api/attester: our public signing key (and any earlier ones). See Public key for how to check a signature.GET /badge/<certificate ID>.svg: a live badge (?style=pill,?theme=dark).
curl https://verifiedwallet.io/api/verify/0x71c7656ec7ab88b098defb751b7401b5f6d8976f
{ "wallet": "0x71c7…976f",
"certificates": [{ "id": "VW-7K3Q-M2XA", "tier": 2, "chain": "evm", "issuedAt": "…", "kycStatus": "verified", "revoked": false, … }] }
Embed a badge that always shows the certificate's current status:
<a href="https://verifiedwallet.io/cert?id=VW-7K3Q-M2XA">
<img src="https://verifiedwallet.io/badge/VW-7K3Q-M2XA.svg" alt="VerifiedWallet certificate" height="40">
</a>
Verify API: getting started
- We give you two keys:
vw_test_…andvw_live_…. Keep them on your server; never put them in a web page or app. - Create a verification for your customer. You get a
url. - Send the customer there (redirect or link). They connect their wallet and sign one message (free, nothing moves), then complete identity or company checks if the tier includes them. You cover the cost; they never pay.
- We send you a
verification.completedwebhook, and laterverification.updatedas identity, AML or company results arrive. You can also fetch the verification at any time. - If you set
return_url, the customer gets a button back to your site, with?verification=ver_…added.
Test keys run the real signing flow, but identity, AML and company results are simulated straight away, the certificate is marked test and kept out of the public register, and nothing is billed. Build against test, then switch the key.
Authenticate every call with Authorization: Bearer vw_live_… (or vw_test_…). Each key only sees its own mode's verifications.
Create a verification
POST /api/v1/verifications
tier: 1 wallet ownership · 2 + identity (ID document, liveness, face match) · 3 + AML (identity screened against sanctions and PEP lists, wallet screened on-chain) · 4 Business: the company checked against its registry, its key people identity-verified, and the wallet screened. Multisig wallets (Bitcoin, XRP, Tron) and Safes are supported.reference(optional): your own ID for the customer, returned on everything.wallet,chain(optional): require this exact wallet; anything else is refused.return_url(optional): where the customer goes back to. Its site must be on your account's allowed list.business(tier 4, optional):{ "company_name", "country" (2 letters), "registration_number" }, so the customer isn't asked.monitor(tiers 3 and 4): re-screen the wallet every 30 days and alert you if the risk changes.metadata(optional): up to 20 string values, returned as given.
curl https://verifiedwallet.io/api/v1/verifications \
-H "Authorization: Bearer vw_test_…" \
-H "Content-Type: application/json" \
-d '{
"tier": 3,
"reference": "customer-1842",
"return_url": "https://app.example.com/wallets/verified",
"wallet": "0x71c7656ec7ab88b098defb751b7401b5f6d8976f",
"monitor": true
}'
{
"id": "ver_3f9a1c0b7e44d2a9f61c",
"object": "verification",
"mode": "test",
"tier": 3,
"status": "pending",
"reference": "customer-1842",
"url": "https://verifiedwallet.io/start?tier=3&vs=vs_…",
"expiresAt": "2026-10-22T09:00:00.000Z",
…
}
The link lasts 7 days and works once.
Retrieve and list
GET /api/v1/verifications/<id>: the verification and, once issued, the certificate's current results.GET /api/v1/verifications?limit=20: your latest, newest first.GET /api/v1/usage?month=2026-10: billable counts for a month and, with a live key, what the invoice comes to so far.POST /api/v1/verifications/<id>/monitoring{ "enabled": false }: stop monitoring a wallet (ortrueto start it on a completed tier 3 or 4 verification).
{
"id": "ver_3f9a1c0b7e44d2a9f61c",
"status": "completed",
"certificateId": "VW-7K3Q-M2XA",
"certificate": {
"id": "VW-7K3Q-M2XA",
"url": "https://verifiedwallet.io/cert?id=VW-7K3Q-M2XA",
"chain": "evm",
"wallet": "0x71c7656ec7ab88b098defb751b7401b5f6d8976f",
"tier": 3,
"identity": { "status": "verified", "provider": "didit" },
"aml": { "status": "clear", "networks": [{ "network": "ETH", "riskScore": 4, "severity": "LOW" }, …] },
"business": null,
"account": null,
"revoked": false,
"test": false,
"core": { … },
"attestation": { "alg": "ES256", "kid": "ZlARoHYj…", "sig": "…" }
}
}
status is pending until the customer signs, then completed. Identity, AML and company results inside certificate can still be pending for a few minutes after that; each change sends a webhook. Every result carries the certificate's signed core and our ES256 attestation: check them against /api/attester and you don't need to trust our API's word.
Webhooks
We POST JSON to your account's webhook URL: { "id", "type", "created", "mode", "data": { "verification": … } }, with the full verification as above. Events:
verification.completed: the customer signed; the certificate is issued.verification.updated: an identity, AML or company result arrived or changed.certificate.revoked: we revoked the certificate.monitoring.alert: a monitored wallet's AML result changed on re-screening.ping: a test we send when you ask.
Answer 2xx quickly; we retry a few times. Check the VerifiedWallet-Signature header (t=<unix time>,v1=<hex>), an HMAC-SHA256 of "<t>.<raw body>" with your webhook secret:
import crypto from "node:crypto";
// Express-style handler: read the RAW body, not parsed JSON.
export function verifyVerifiedWalletWebhook(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // older than 5 minutes
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
Pricing
Pay as you go, no setup fee, no minimum. Test keys are free. Invoiced monthly in US dollars for the previous month's live usage, payable by card or bank transfer within 14 days.
| Per completed verification | Price |
|---|---|
| Wallet ownership (tier 1) | $0.50 |
| + Identity (tier 2) | $2.00 |
| + AML screening (tier 3) | $3.50 |
| Business: company + up to 3 key people (tier 4) | $25.00 |
| Each extra key person | $1.00 |
| Monitoring, per wallet per month (re-screens included) | $1.00 |
Growth: $299 a month including $400 of usage, plus a named contact. Enterprise: volume pricing, an uptime commitment and a data processing agreement. Talk to us.
Errors and limits
Errors are JSON { "error": "…" } with a plain-English message: 400 bad request, 401 missing or wrong key, 404 not found, 409 already used, 429 slow down. The API is versioned (/api/v1); we add fields but never remove or rename them within a version. Machine-readable spec: openapi.json.
Try it live
This starts a real test verification on our demo account, exactly as your server would, and shows what your server would get back. Sign with any wallet you have; the identity, AML and company results are simulated.