docs // $ man daoaml(1) · version: v2.4.1 · last edit: 2026-05-04

The whole manual, on one page

Authentication, the four endpoints that matter, every webhook payload, the CLI, and the three SDKs. No "contact sales for advanced features." If it exists, it's documented here.

# 01

Quickstart — first verdict in 30 seconds

You'll need an API key. Sign up at app.daoaml.com, copy the key from settings → keys, and:

# 1. Install the CLI (npm, brew, scoop, or curl)
$ npm i -g @daoaml/cli

# 2. Set your key
$ export DAOAML_KEY="sk_live_…"

# 3. Run a check
$ daoaml check 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

→ verdict_id: vd_01HZK4M7Q3X9
→ score: 5/100 (LOW)
→ verdict: https://daoaml.com/v/vd_01HZK4M7Q3X9

That's the whole loop. The verdict link is what you forward to a compliance team — it's a public, signed page they can verify on their side.

# 02

Authentication

All requests use bearer-token auth. Pass the API key in the Authorization header. Keys are environment-scoped — sk_test_… hits the sandbox, sk_live_… hits production.

API keys

curl https://api.daoaml.com/v1/check \
  -H "Authorization: Bearer sk_live_***" \
  -H "Content-Type: application/json" \
  -d '{"chain":"ethereum","address":"0xd8dA…"}'

Keys never leave the dashboard except as ***. Rotate any time — old key revokes immediately, no grace window.

Rate limits

Limits are per-account, not per-key. Live tier: 240 req/min, with a 30-request burst. Sandbox: 60/min. The response always carries:

X-RateLimit-Limit: 240
X-RateLimit-Remaining: 237
X-RateLimit-Reset: 1714826400

Hit a 429? Back off using the Retry-After seconds. We never charge for rate-limited responses.

# 03

REST endpoints

Four endpoints. That's all there is. Base URL: https://api.daoaml.com/v1.

POST/v1/checksingle address
GET/v1/verdict/:idretrieve verdict
POST/v1/check/batchup to 1000 addresses
GET/v1/listssanctions diff

POST /v1/check

Run an AML check on a single address. Returns a verdict in 0.8–2.4s p95. Costs $2.99 per call on the live tier (free in sandbox).

Request body
chainrequiredstringOne of ethereum, bitcoin, tron, solana, … (full list at GET /v1/chains).
addressrequiredstringAddress in native format. Checksummed EVM is recommended but not required.
depthintegerIndirect-exposure hop depth, 1–5. Default: 3.
webhook_urlstringIf set, also POST verdict here on completion.
metadataobjectFree-form, ≤2KB. Echoed back verbatim. Useful for case_id, deal_id.
Example response
{
  "id": "vd_01HZK4M7Q3X9",
  "chain": "ethereum",
  "address": "0xd8dA…",
  "score": 5,
  "badge": "LOW",
  "categories": ["individual", "public_figure"],
  "exposure": {
    "direct": { "sanctions": 0, "mixers": 0 },
    "indirect_3hop": { "darknet": 0.0001 }
  },
  "verdict_url": "https://daoaml.com/v/vd_01…",
  "signed_at": "2026-05-04T11:22:43Z",
  "signature": "ed25519:7Q3X…"
}

GET /v1/verdict/:id

Retrieve a verdict by its ID. Verdicts are immutable and cached forever — same call returns the same payload byte-for-byte. Free.

$ curl https://api.daoaml.com/v1/verdict/vd_01HZK4M7Q3X9 \
    -H "Authorization: Bearer sk_live_***"

POST /v1/check/batch

Submit up to 1,000 addresses in one call. You get back a batch_id. Poll or use a webhook. Volume discount applies (see pricing).

{
  "items": [
    { "chain": "ethereum", "address": "0x…" },
    { "chain": "bitcoin",  "address": "bc1…" }
  ],
  "webhook_url": "https://your.app/wh/aml"
}

GET /v1/lists

Daily diff of every sanctions list we track — OFAC SDN, EU CFSP, UK OFSI, UN, plus 14 chain-specific darknet/mixer lists. Supports ?since= for delta polling. Free.

# 04

Webhooks

Three event types: verdict.completed, verdict.escalated, list.updated. We POST a JSON payload, sign it with HMAC-SHA256, and retry up to 6 times with exponential backoff (1m → 1h).

POST /your/webhook
X-DAOAML-Event: verdict.completed
X-DAOAML-Signature: t=1714826400,v1=a3f9…

{
  "event": "verdict.completed",
  "data": { /* full verdict object */ }
}

Verify the signature: HMAC-SHA256 over ${'{'}t{'}'}.${'{'}body{'}'} using your webhook secret. Reject anything older than 5 minutes — replay defense.

# 05

Command-line interface

The CLI is a thin wrapper over the API, optimized for shell pipelines and one-off checks.

$ daoaml --help

USAGE:  daoaml <command> [args]

COMMANDS:
  check     <chain:address>     run a single check
  batch     <file.csv>          submit a CSV (chain,address)
  verdict   <id>                fetch by id, prints JSON
  watch     <address>           poll daily, alert on change
  lists     diff [--since=…]    sanctions delta
  login                         interactive key setup
  whoami                        show current account & tier

FLAGS:
  --json          machine-readable output
  --quiet         exit 0/1 only, no stdout
  --depth=N       indirect exposure hops (1..5)

Pipe-friendly. daoaml watch 0x… --quiet && alert is a perfectly valid one-liner.

# 06

SDKs

Three first-party SDKs. All thin, all open-source, all type-safe.

Node / TypeScript — @daoaml/sdk

import { Daoaml } from "@daoaml/sdk";

const aml = new Daoaml({ apiKey: process.env.DAOAML_KEY });

const verdict = await aml.check({
  chain: "ethereum",
  address: "0xd8dA…",
});

if (verdict.score > 70) await refundAndFreeze(verdict);

Python — daoaml

from daoaml import Daoaml

aml = Daoaml(api_key=os.environ["DAOAML_KEY"])
v = aml.check(chain="ethereum", address="0xd8dA…")
if v.score > 70:
    refund_and_freeze(v)

Go — github.com/daoaml/go-sdk

aml := daoaml.New(os.Getenv("DAOAML_KEY"))
v, err := aml.Check(ctx, &daoaml.CheckReq{
  Chain: "ethereum",
  Address: "0xd8dA…",
})
if err != nil { return err }
if v.Score > 70 { return refundAndFreeze(v) }
# 07

Error codes

Stable, documented, exhaustive. We don't add new ones without a minor-version bump.

400 invalid_addressstrAddress fails native checksum / format.
400 unsupported_chainstrChain not in /v1/chains.
401 invalid_keystrBearer missing/wrong/revoked.
402 insufficient_creditstrPre-pay tier ran out. Top up.
404 verdict_not_foundstrID is malformed or older than 7y.
429 rate_limitedstrSee Retry-After.
503 chain_laggingstrIndexer >30 blocks behind. Retry shortly.
500 internalstrWe pay for it. X-Trace-Id attached.