API reference
Base URL https://aml.progonka.com. Authenticate with Authorization: Bearer <key>. Requests and responses are JSON.
Where to start
Decide which of the two questions you are asking. These are not two quality tiers — they are different questions with different costs.
| Call | Answers | Latency | Price |
|---|---|---|---|
| POST /api/v1/screen | Is this address itself on a list? | <50 ms, inline | 0.02 USD |
| POST /api/v1/checks | Where did the money come from (up to 3 hops)? | 202, then webhook | 0.30 USD |
Instant screen
POST /api/v1/screen
curl -X POST https://aml.progonka.com/api/v1/screen \
-H "Authorization: Bearer $PLUS_AML_KEY" \
-H "Content-Type: application/json" \
-d '{"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"}'
One indexed lookup, no node traffic. It answers only about the address itself and knows nothing about its counterparties. This is the call to make when a payment is waiting on the answer.
Deep check
POST /api/v1/checks
curl -X POST https://aml.progonka.com/api/v1/checks \
-H "Authorization: Bearer $PLUS_AML_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "address",
"target": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"direction": "inbound",
"depth": 3,
"external_ref": "order-1841",
"webhook_url": "https://your.host/hooks/aml"
}'
- kind
- address — screen a wallet. transaction — put a transaction id in target; the trace then runs from the counterparty: the sender for inbound, the recipient for outbound.
- direction
-
inbound — where the money came from. The
question when accepting a payment.
outbound — where it is going. The question before sending one.
both — both, with the traversal budget split between them. - depth
- 1–3. Depth affects how long the walk takes, not what it costs.
- webhook_url
- Where to deliver the result. Without it, poll GET /api/v1/checks/{id}.
The 202 comes back immediately:
{
"id": "9f1c…",
"status": "pending",
"preliminary": {
"risk_score": 0,
"risk_level": "CLEAN",
"verdict": "PASS",
"basis": "list match only; the graph walk has not run yet"
}
}
For a sanctioned address the preliminary verdict is already the final one — the walk is not run at all in that case.
The result
GET /api/v1/checks/{id}
{
"id": "9f1c…",
"status": "done",
"risk_score": 63,
"risk_level": "MEDIUM",
"verdict": "REVIEW",
"findings": [
{
"address": "TXyz…",
"category": "frozen_by_issuer",
"hop": 2,
"share_of_volume": 0.184,
"amount_usdt": 18400.0,
"contribution": 51.0,
"path": ["TSubject…", "TMid…", "TXyz…"]
}
],
"coverage": {
"complete": false,
"note": "TBA6Cy… is a hub, funds commingled — branch stopped",
"nodes_expanded": 47,
"list_version": "345d06…",
"engine": { "depth": 3, "min_branch_share": 0.005, "…": "…" }
}
}
How to read it
- risk_score
- 0–100, and objective: each finding contributes its category weight times its share of volume times the decay for its hop.
- verdict
- PASS / REVIEW / FAIL — this is your policy applied to the score. The thresholds are set per account (currently 50 and 75).
- share_of_volume
- The fraction of traced volume that reached this address. It is what stops a single speck of dust from a scammer condemning a wallet.
- coverage.complete
- false means a limit cut the walk short, and note says which. A low score with complete: false must not be read as "clean".
- coverage.list_version
- The snapshot of the lists the verdict was decided on, for reproducibility.
Monitoring
POST /api/v1/monitors
curl -X POST https://aml.progonka.com/api/v1/monitors \
-H "Authorization: Bearer $PLUS_AML_KEY" \
-d '{"address": "T…", "label": "hot wallet", "webhook_url": "https://your.host/hooks/aml"}'
The address is polled every 15 minutes. When a listed counterparty turns up among its new transfers, a monitor.alert is delivered. Billed at 1.50 USD per address per month, charged on subscribing and on renewal.
GET /api/v1/monitors lists them, GET /api/v1/monitors/{id}/alerts returns alerts, DELETE /api/v1/monitors/{id} unsubscribes.
Webhooks
A JSON POST to your URL, retried three times with growing backoff.
{ "event": "check.completed", "check": { … } }
{ "event": "monitor.alert", "monitor_id": "…", "address": "T…", "alert": { … } }
Errors
| Code | When |
|---|---|
| 400 / 422 | Malformed address or transaction id. Address checksums are verified, so a typo is rejected rather than screened as if it were a real address. |
| 401 | Key missing, revoked or wrong. |
| 402 | Balance does not cover the call. The body carries your balance and the price. |
| 404 | No such check or monitor, or it belongs to another partner. |
| 429 | Rate limited. |
What the service does not do
- It does not cluster addresses — the database is built from open sources, not from proprietary intelligence.
- It does not work outside TRON: TRC-20 only.
- It cannot see what is not yet in the open lists; a fresh scam reaches the database in days, not instantly.
- It is not a regulatory determination.