Know Your Transaction / Address (KYT & KYA)
Risk-score a blockchain address (KYA) or transaction (KYT) for compliance screening. Both run through the same asynchronous job API described below.
Authentication
KYT/KYA endpoints accept an API key via the x-api-key header:
-H "x-api-key: llk_your_api_key_here"
Create and manage keys from Account → API Keys. (Session-based Clerk JWTs via
Authorization: Bearer … also work from the dashboard, but programmatic callers
should use an API key.)
KYT vs KYA — it's auto-detected
You call the same endpoint for both. The service picks the analysis type from your payload:
| You send | Analysis run | api_type in the result |
|---|---|---|
address | KYA (Know Your Address) | KYA |
txid | KYT (Know Your Transaction) | KYT |
A POST /kyt/job with an address returns a KYA
result. That is expected, not a bug: the analysis type follows the payload, not
the path.
The flow: submit, then poll
Analysis is asynchronous. You submit a job, get a request_id back
immediately, then poll that id until the status is completed.
POST /api/v1/kyt/job -> 202 { request_id, status: "queued" }
GET /api/v1/kyt/job/{id} -> 200 { status: "queued" | "completed", response }
1. Submit a job
curl -X POST "http://localhost:8090/api/v1/kyt/job" \
-H "x-api-key: llk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"chain": "bitcoin",
"crawlTimeout": 60000,
"reference_id": "customer-12345"
}'
For a transaction (KYT), send txid instead of address:
-d '{ "txid": "0x1234…", "chain": "ethereum", "reference_id": "customer-12345" }'
Request fields
| Field | Required | Description |
|---|---|---|
address | one of address / txid | Address to screen (runs KYA) |
txid | one of address / txid | Transaction hash to screen (runs KYT) |
chain | yes | e.g. bitcoin, ethereum |
crawlTimeout | no | Max crawl time in ms (e.g. 60000) |
reference_id | no | Your own correlation id, echoed back on the result — for example, store an internal customer ID or case ID here to associate the analysis with one of your customers or cases. (referenceId is accepted as a deprecated alias.) |
Response — 202 Accepted
{
"success": true,
"data": {
"request_id": "0692ee28-2942-4b46-b906-4fbee0d69c1b",
"status": "queued",
"reference_id": "customer-12345",
"created_at": 1783580778153
}
}
Hold on to request_id — that is what you poll with.
2. Poll for the result
curl "http://localhost:8090/api/v1/kyt/job/0692ee28-2942-4b46-b906-4fbee0d69c1b" \
-H "x-api-key: llk_your_api_key_here"
While running, status is queued. Poll every few seconds until it is
completed; typical jobs finish in a few seconds.
Response — 200 OK (completed)
{
"success": true,
"data": {
"request_id": "0692ee28-2942-4b46-b906-4fbee0d69c1b",
"status": "completed",
"reference_id": "customer-12345",
"response": {
"api_type": "KYA",
"chain": "bitcoin",
"risk_level": "HIGH",
"risk_score": 81.9,
"response_id": "522f0569-08e4-4ce8-96c8-10a5b0117e58",
"risk_reason": "Entity with highest risk score is txid 367f5e71… Its top risk rule is 'tagScore' with score 81.90.",
"rule_scores": {
"tag_score": 10,
"is_sanctioned": 0,
"is_blacklisted": 0,
"receive_count": 8,
"address_type": 2,
"active_duration": 1
},
"target_summary": {
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"tags": [{ "name": "satoshi-nakamoto", "type": "label", "display": "Satoshi Nakamoto" }],
"balances": [{ "asset": "BTC", "amount": 57.23311933, "usd": 3595393.05 }]
}
}
}
}
3. Full response (optional)
For the complete payload including graph and performance metadata:
curl "http://localhost:8090/api/v1/kyt/job/{request_id}/fullresponse" \
-H "x-api-key: llk_your_api_key_here"
Two IDs, don't mix them up
request_id identifies your job — you get it from the
submit call and use it to poll (GET /kyt/job/{request_id}).
response_id identifies the finished result, returned
inside response; store it for your records, but it is not the id you
poll with.
Reading the result
| Field | Meaning |
|---|---|
risk_level | LOW | MEDIUM | HIGH |
risk_score | 0–100 composite score |
risk_reason | Human-readable driver of the score |
rule_scores | Per-rule contributions (is_sanctioned, tag_score, …) |
target_summary.tags | Known labels/tags for the address |
target_summary.balances | Current holdings and USD value |
Credits
Each completed analysis consumes credits from your account (KYA and KYT have a
small per-run minimum, with additional cost scaling to crawl depth/complexity).
A 402 response means the account behind the API key is out of credits — top up
from Account → Plan.
Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
402 | Insufficient credits |
404 | Unknown request_id when polling |
Legacy synchronous API (deprecated)
POST /api/v1/kyt/analyze and POST /api/v1/kya/analyze are
deprecated. They block until the analysis completes (10–60s or
more) and offer no way to recover a result if the connection drops. They remain
available for backwards compatibility, but new integrations should use the
asynchronous job flow above (POST /kyt/job + polling).