Quickstart — first verdict in 30 seconds
Anonymous flow needs no signup — 3 checks / month per IP+browser are free. Past that, sign in (magic-link or wallet) and either burn the free quota of a paid plan or pay per call via x402.
# Anonymous one-shot — same shape the client-app uses $ curl -X POST https://daoaml.com/api/v1/check \ -H "Content-Type: application/json" \ -d '{"address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","blockchain":"ethereum"}' → { "result": { "risk_score": 5, "risk_level": "LOW", "check_id": "chk_01HZK4M7Q3X9", ... }, "quota": { "limit": 3, "used": 1, ... } } # The check_id powers permalinks at https://daoaml.com/v/<short_id>
A verdict check_id is the handle compliance teams share — it resolves to daoaml.com/v/<id>, an immutable, signed permalink they can verify on their side.
Authentication
Three identity paths: anonymous (no auth, IP-quota), cookie session (magic-link email or SIWE wallet — 30-day cookie), and API key (Business plan, machine clients). All paths share the same endpoint surface — the server picks the quota path based on what you sent.
Magic-link (email)
$ curl -X POST https://daoaml.com/api/v1/auth/magic-link \ -H "Content-Type: application/json" \ -d '{"email":"you@domain.com"}' → 202 Accepted; email contains a one-time token link $ # Recipient clicks the link → $ curl https://daoaml.com/api/v1/auth/verify?token=<token> → 302 to /me + Set-Cookie: client_session=...; HttpOnly $ curl -X POST https://daoaml.com/api/v1/auth/logout → 204; cookie cleared
Wallet sign-in (EIP-4361 / SIWE)
$ curl -X POST https://daoaml.com/api/v1/auth/wallet/nonce \ -d '{"address":"0x..."}' → { "message": "...EIP-4361 SIWE...", "nonce": "...", "expiration_time": "..." } # Client signs `message` via personal_sign $ curl -X POST https://daoaml.com/api/v1/auth/wallet/verify \ -d '{"message":"...","signature":"0x..."}' → 200; Set-Cookie: client_session=...; account upserted by wallet_address
API keys (Business plan)
$ # With an active cookie session: $ curl -X POST https://daoaml.com/api/v1/me/api-keys \ -H "Cookie: client_session=..." \ -d '{"label":"prod-bot"}' → { "id": "...", "key": "daoaml_...", "label": "prod-bot" } ← shown ONCE $ curl https://daoaml.com/api/v1/check \ -X POST -H "X-API-Key: daoaml_..." \ -d '{"address":"0x...","blockchain":"ethereum"}'
The key is returned in plaintext exactly once at creation — store it. GET /me/api-keys lists only metadata; DELETE /me/api-keys/{key_id} revokes immediately, no grace window.
Address checking
Base URL: https://daoaml.com/api/v1. All endpoints return JSON unless noted.
POST /check
Score an address. Quota: anonymous 3/mo (IP+browser), Free 3/mo, paid plans burn the included quota first then a pack-credit. Latency p95 ≈ 0.8–2.4s.
"tron". ethereum, bitcoin, tron, solana, bsc, polygon, arbitrum, base, ton, … (≈25 supported).false. When true, response includes address_info and direct_exposure.{
"result": {
"address": "0xd8dA...",
"blockchain": "ethereum",
"risk_score": 5,
"risk_level": "LOW",
"risk_categories": [{ "slug": "individual", ... }],
"entities": [...],
"address_info": /* if include_details */,
"direct_exposure": /* if include_details */,
"checked_at": "2026-05-22T11:22:43Z",
"check_id": "chk_01HZK4M7Q3X9"
},
"quota": { "limit": 3, "used": 1, "resets_at": "..." }
}
GET /address/{address}
Same payload as POST /check, GET-shaped for cache-friendly callers. Chain is passed as ?blockchain=…; defaults to tron.
$ curl "https://daoaml.com/api/v1/address/0xd8dA…?blockchain=ethereum&include_details=true"
GET /check/{check_id}
Fetch a frozen check snapshot. Returns 404 for unknown id, 410 Gone if the owner soft-deleted it via DELETE /me/checks/{check_id}. Read-only, redacted for the public audience (no provider attribution, no internal UUIDs).
POST /address/batch
Up to 100 addresses in one request — single blockchain, same include_details flag. Returns a list of AddressCheckResponse objects with shared checked_at and total.
{
"addresses": ["0x...", "0x..."],
"blockchain": "ethereum",
"include_details": false
}
GET /address/{chain}/{addr}/transactions
Per-chain dispatch — identical response shape across 25+ chains. Cursor-paginated.
GET /api/v1/address/{chain}/{addr}/transactions
?limit=25&direction=in|out|all&cursor=&token=
Cabinet (/me)
All /me/* endpoints require an active client_session cookie (magic-link or wallet) or an X-API-Key header bound to the same account.
GET /api/v1/me # current account + plan + quota GET /api/v1/me/checks # personal verdict history GET /api/v1/me/reports # community-reports I submitted GET /api/v1/me/defrost # my Defrost orders GET /api/v1/me/billing # subscription state + pack credits GET /api/v1/me/referrals # referral codes & earnings DELETE /api/v1/me/checks/{check_id} # soft-delete (cascades to share-links) POST /api/v1/me/link-wallet # bind a SIWE wallet to the current account GET /api/v1/me/api-keys # list scoped keys (metadata only) POST /api/v1/me/api-keys # create — plaintext key shown ONCE DELETE /api/v1/me/api-keys/{key_id} # revoke immediately
Community reports
Submit + browse + per-address filter. Verified reports automatically attach to address_labels.
POST /api/v1/community-reports # submit a scam report GET /api/v1/community-reports # public list (status=verified) GET /api/v1/community-reports?address=... # per-address filter GET /api/v1/community-reports/{report_id} # single verified report
Defrost — Source-of-Funds Attestation
PDF report for unfreezing a CEX deposit. Tiers Quick / Standard / Pro (3 / 5 / 7 hops). Pay-per-order — x402 settles $49 USDC on Base.
POST /api/v1/defrost/orders # create order GET /api/v1/defrost/orders/{order_id} # owner-side status + tier + audit GET /api/v1/defrost/orders/{order_id}/pdf # signed PDF (owner only) GET /api/v1/defrost/verify/{order_no} # public recipient-side verify (no auth)
Plans & billing
Crypto-first checkout via NowPayments and Cryptomus (USDT, USDC, BTC, ETH and more). Fiat available via Stripe and YooMoney in supported regions.
GET /api/v1/plans # public catalog POST /api/v1/billing/checkout body = { "plan_code", "provider", "currency" } # → { "redirect_url": "..." }
Provider IPN webhooks (/api/v1/billing/webhook/{provider}) are intentionally not part of the public surface — they are provider-callable only and excluded from /openapi.json.
x402 — pay per call, no signup
HTTP 402 Payment Required, finally implemented. Agents (or any non-browser caller) can settle in USDC on Base instead of holding an account — handy for one-off calls from a script or an LLM-driven workflow that doesn't want to manage credentials.
Set Accept: application/x402+json on POST /api/v1/check. Server replies 402 with the price table in x402.accepts[] (one entry per network: base, base-sepolia). Pay the indicated amount of USDC to pay_to, encode the proof {network, tx_hash} as base64, and retry the same request with X-Payment: <proof>. The verdict comes back on that retry.
# 1. Discover the price $ curl -X POST https://daoaml.com/api/v1/check \ -H "Accept: application/x402+json" \ -H "Content-Type: application/json" \ -d '{"address":"0x...","blockchain":"ethereum"}' → 402 { "x402": { "accepts": [{"network":"base","amount":"0.10", "asset":"USDC","pay_to":"0x...", "resource":"/api/v1/check"}, ...] } } # 2. Pay USDC on Base, base64-encode {"network":"base","tx_hash":"0x..."} # 3. Retry with proof $ curl -X POST https://daoaml.com/api/v1/check \ -H "X-Payment: eyJuZXR3b3JrIjoiYmFzZSIsInR4X2hhc2giOiIweC4uLiJ9" \ -d '{"address":"0x...","blockchain":"ethereum"}' → 200 { "result": { "risk_score": 5, ... } }
Priced endpoints: /api/v1/check ($0.10) and /api/v1/defrost/orders ($49). Browser / curl requests without the agent Accept header keep the normal anonymous-quota / session flow — x402 is opt-in.
Errors
FastAPI / Starlette error envelope. error is a short slug; message a human hint.
blockchain.SUPPORTED_BLOCKCHAINS.X-API-Key on a protected route.X-Payment proof. Body carries x402.accepts.check_id / order_id / short_id, etc.plan, limit, used, resets_at.OpenAPI & llms.txt
Two machine-readable surfaces. Either one is enough to wire an agent or generate clients.
Discovery: /.well-known/api-catalog (RFC 9727), /.well-known/oauth-authorization-server (RFC 8414).