Transaction Decision API
Integrate transaction checks for TRON, Ethereum and TON, understand coverage and handle retries.
Check a transaction before recording a payment
ChainZap checks a blockchain transaction before your application records a payment as received. One response combines transaction facts, risk signals and, if you ask for it, a comparison with the recipient, token and amount you expected.
What you can check
TRON, Ethereum mainnet and TON mainnet adapters are implemented. TRON checks are live for every new organization. TON is a preview whose checks of executed transactions currently return LIMITED_DATA; Ethereum checks are activated by support on request. Sign in with your ChainZap account to the developer dashboard, create an API key and start with the canonical transaction quickstart.
POST /v1/transaction/check: the canonical detailed contract 0.3 response. The network is required; expected payment details enable verification.POST /v1/check: send a transaction hash. The network and the expected payment details are optional. The response is a short assessment with full evidence indetails.POST /v1/wallet/check: send a wallet address. The network is read from its format. The response is a state, a coverage level and reason codes with per-module facts indetails; see wallet check.GET /v1/usage: your organization's quota and recent usage.
Call the API from your server and send your API key in the X-API-Key header.
Interpret the whole response
A successful HTTP response does not mean a payment is confirmed or free of risk. For /v1/check, read state, risk_level and coverage together with the transaction state, the matching flags, the freshness data and the reasons in details. The canonical /v1/transaction/check returns those detailed fields at the top level. null means unknown or not requested, depending on the field. Never treat missing evidence as a clean result.
Continue with the quickstart, then read data completeness and idempotency.
Your first transaction check
Get access
Sign in with your ChainZap account to the developer dashboard. An organization is created for you automatically and you become its owner; an invitation code is needed only to join an existing organization. Create a key on the API keys page and store it in your server's secret store. TRON checks are live at once: a sandbox key lets you test for free, and a plan for live checks is bought on the Plan and billing page. Contact support to invite colleagues to your organization.
Send your first request
This example uses a fictional key and transaction hash. Replace them on your server. All amounts are decimal strings. Store your idempotency key together with the payment operation, so that it survives a process restart.
curl --include --max-time 15 'https://api.chainzap.io/v1/transaction/check' \
-H 'Content-Type: application/json' \
-H 'X-API-Key: cz_live_000000000000.fictional_example_only' \
-H 'Idempotency-Key: merchant-order-1001-check-1' \
-H 'X-Request-ID: merchant-order-1001-attempt-1' \
--data '{"network":"tron","expected_recipient":"TJRabPrwbZy45sbavfcjinPJC18kjpRTv8","expected_token":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","expected_amount":"1250.000001","tx_hash":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}'
Read X-Request-ID in the response headers and request_id in the JSON body. Keep this identifier for support. This canonical endpoint requires network. See status axes before consuming a result; POST /v1/check is the optional short response.
Verify expected payment details
{
"network": "tron",
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"expected_recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"expected_token": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"expected_amount": "1250.000001"
}
The example addresses are public sample addresses, not payment instructions. Match an exact token contract, not a symbol. Read all three match flags; they refer to the same selected transfer. See matching.
Consume contract 0.3
Use verification_final and integrity_status for payment verification, then evaluate risk_status and recommended_action separately. Pending is NOT_EVALUATED, never MATCH. Final MATCH with risk_status: INSUFFICIENT confirms the payment comparison but requires MANUAL_REVIEW, not automatic credit or payout approval. Read risk_retryable independently from retryable. The response examples show these branches.
Close a payout automatically
Without context about your side, a final MATCH with risk_status: NO_MATERIAL_SIGNAL and no reason to review gives CONFIRM_INTERNAL_STATE: the chain and the risk screen are in order, but ChainZap cannot see whether this payment is the one you owe or whether it was already settled. It is not a refusal: confirm in your own records that the payout is still owed and not already marked paid, then close it. The same action without a MATCH (no expected fields sent) has not compared the payment: do not close a payout on it.
To reach PROCEED, tell ChainZap what the payment is for: send direction: "OUTGOING", workflow_type: "PAYOUT" and the payout's external_reference together with the expected fields, or record the obligation first and send its external_reference with the check. A clean, final match against that recorded outgoing obligation is PROCEED; without an external_reference the best answer stays CONFIRM_INTERNAL_STATE, unless the check also sends customer_context.credit_status: "NOT_CREDITED", which alone is enough for PROCEED unless allocation_status is UNKNOWN (see statuses). direction and workflow_type are accepted without the obligation ledger, but on their own they never reach PROCEED; with direction: "OUTGOING", a payout that is not found also carries ATTEMPT_MAY_STILL_LAND: do not pay again. external_reference and the other obligation fields need the obligation ledger and answer 403 ledger_not_enabled where it is off.
Handle uncertainty
If the connection closes before you receive a response, retry with the same body and the same Idempotency-Key. Never create a new key to get around an uncertain result. Retry a received error only when error.retryable is true; honor Retry-After and cap the number of attempts. A stored error can be replayed unchanged: retryable does not force a new provider check.
See the Python and TypeScript examples for bounded retries and usage for quota inspection.
Check a wallet too
The same key screens a counterparty's address: POST /v1/wallet/check with {"address": "..."} returns a state, coverage and reason codes in the same shape, and is billed when a state is produced. See wallet check.
One transaction hash, one check
POST /v1/check needs only tx_hash. The API reports facts, risks and data gaps. Your application decides what to do with the payment. Sign in with your ChainZap account to the developer dashboard and create a server key on the API keys page.
A first result
Set CHAINZAP_API_KEY, TX_HASH and a persisted operation ID CHECK_ID on your server. These examples make one request only when you run them. For test data without provider calls, use a sandbox key. Never put a key in browser code. The request takes fewer than ten lines of application code; check the HTTP status before interpreting the result.
curl --include --max-time 15 https://api.chainzap.io/v1/check \
-H "X-API-Key: $CHAINZAP_API_KEY" -H "Idempotency-Key: $CHECK_ID" \
-H 'Content-Type: application/json' --data "{\"tx_hash\":\"$TX_HASH\"}"
const response = await fetch("https://api.chainzap.io/v1/check", {
method: "POST", signal: AbortSignal.timeout(15000),
headers: {"Content-Type": "application/json", "X-API-Key": process.env.CHAINZAP_API_KEY,
"Idempotency-Key": process.env.CHECK_ID},
body: JSON.stringify({tx_hash: process.env.TX_HASH})
});
const result = await response.json();
if (!response.ok) throw new Error(result.error.code);
import os, requests
response = requests.post("https://api.chainzap.io/v1/check", timeout=15,
headers={"X-API-Key": os.environ["CHAINZAP_API_KEY"],
"Idempotency-Key": os.environ["CHECK_ID"]},
json={"tx_hash": os.environ["TX_HASH"]})
result = response.json()
response.raise_for_status()
<?php
$ch = curl_init('https://api.chainzap.io/v1/check');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-API-Key: '.getenv('CHAINZAP_API_KEY'), 'Idempotency-Key: '.getenv('CHECK_ID')],
CURLOPT_POSTFIELDS => json_encode(['tx_hash' => getenv('TX_HASH')])]);
$result = json_decode(curl_exec($ch), true);
if (curl_errno($ch) || curl_getinfo($ch, CURLINFO_HTTP_CODE) >= 400) throw new RuntimeException($result['error']['code'] ?? 'transport_error');
curl_close($ch);
Network discovery
The accepted network names are tron, eth and ton; aliases are rejected. An explicit network restricts the search to that network. Hash shape, a 0x prefix, base64 and provider response order never determine the network, in the sandbox included.
Without network, ChainZap reads facts only in supported, activated networks enabled for your organization. details.checked_networks reports that scope; uniqueness says nothing about other chains. AML screening does not run across networks. All other checked networks must conclusively report no transaction. Provider failure, indexing gaps or timeouts do not count as absence. A single positive result plus an unknown result requires network.
Automatic detection uses the same provider-call budget as explicit selection, whether one network is in scope or several. Providers must still confirm that the transaction hash belongs to the network reported. A read whose price is not configured is recorded as unknown cost, never as zero.
NETWORK_AMBIGUOUS means several networks found the transaction. NETWORK_REQUIRED means the available context cannot prove a unique result: for example one network found it while another could not answer, or no networks are enabled. When every checked network confirms the transaction is absent, the answer is 404 transaction_not_found instead. Both use HTTP 422, state: insufficient_input, network: null, error.retryable: false, error.required_field: network, error.candidates and error.checked_networks. Specify the network and use a new idempotency key. Retrying the same body will replay the same error.
Short and detailed response
| Field in the short response | Meaning |
|---|---|
request_id, network |
Correlation ID and resolved canonical network. |
state |
clear, review, high_risk, limited_data: a check result, never a payment instruction. |
risk_level |
low, moderate, high, severe, unknown. Sanctions raise this to severe; a fake token raises it to at least high. |
coverage |
complete or partial, within the documented scope. |
reason_codes |
Stable strings. Accept unknown future codes. |
details |
Transaction/finality, selected index and all transfers with decimal-string raw_amount, matching, authenticity, AML/sanctions, source timestamps, limitations and full reason objects. |
state is details.overall_state in lowercase. Detailed reason objects live in details.reasons; strings and objects are never mixed. Known high risks remain visible with partial coverage. A requested comparison with the value null is unfinished. All expected_* fields must match the same transfer; several full matches are ambiguous.
The canonical /v1/transaction/check keeps uppercase states, coverage: complete or partial and 2 to 5 reason objects. /v1/usage and X-API-Key are unchanged. /v1/check returns HTTP 404 transaction_not_found for a verified explicit-network absence; the canonical endpoint keeps HTTP 200 transaction_state: not_found. A pending check is HTTP 200 with review/limited_data, never clear, and is not charged. Both endpoints use the same limits, quota and costs. Idempotency keys are shared per organization: switching the endpoint or changing the body conflicts. Stored results, including the resolved network and the errors answered after the check was accepted, replay without another provider check; 429 and 5xx are never stored. Replay rechecks access.
Ethereum and TON coverage
| Network | Assets with configured KYT mapping | Facts and limitations |
|---|---|---|
| TRON | TRX; official USDT, USDC, USDD | Existing dual-source transaction checks and the 19-confirmation solidification policy. |
| Ethereum mainnet | ETH; official USDT, USDC, WETH ERC-20 | Chain ID 1, receipt status, canonical block inclusion and finalized head, reconciled across two sources. The latest head or any block before the finalized head is insufficient. Ordered ERC-20 logs; no ERC-721 or Approval payments. |
| TON mainnet | TON; official USDT jetton | Mainnet ID -239, two indexed views, transaction hash, account/LT/shard, finalized masterchain inclusion and completed message links. Jetton master/wallet/owner verification and raw message bodies. |
Ethereum internal native transfers need execution traces and are outside this version's scope. ERC-20 logs do not establish a recipient's net balance change for fee-on-transfer or rebasing tokens. Mint, burn and zero-value transfers require review. Unknown decimals leave amount: null; symbols never establish authenticity. Other tokens can have transfer facts but incomplete authenticity/KYT coverage.
TON accepts transaction hashes only, in 64-digit hex (optional 0x) or canonical 32-byte base64/base64url. A message hash or BOC is not silently reinterpreted as a transaction hash. Friendly addresses require a valid checksum; bounceable and non-bounceable normalize to workchain/account. Test-only addresses are rejected. expected_token means jetton master, expected_recipient means wallet owner. An isolated transfer_notification is not proof. Bounces, failed compute/actions, missing descendants and emulation cannot produce clear. Current wallet get-method results are cross-checked with the second index; historical identity changes require further investigation. Finality is provider-attested, not a locally verified validator signature proof.
Ethereum and TON checks are activated per organization by support after live acceptance. AML screening covers the assets the AML source supports on each network; a specific account's entitlement, actual costs and coverage still require live verification. Missing AML or sanctions evidence never defaults to low/clear. See source coverage.
Deterministic response example
This is an illustrative fixture, not a live observation. Expand the complete JSON below.
View full JSON response
{
"coverage": "complete",
"details": {
"aml_risk_level": "low",
"amount": "1250.000001",
"amount_match": true,
"checked_networks": [
"tron"
],
"confirmations": 27,
"coverage": "complete",
"coverage_limitations": {
"product": [
"AML_TRANSACTION_LEVEL_ONLY",
"RISK_STATE_AS_OF_CHECK",
"SANCTIONS_CONFIGURED_LISTS_ONLY"
],
"runtime": []
},
"coverage_status": "OK",
"decimals": 6,
"decision_id": "0199a1b2-7c3d-7e4f-8a9b-0c1d2e3f4a5b",
"direct_sanctions_match": false,
"direction": "OUTGOING",
"environment": "live",
"evidence": {},
"evidence_items": [
{
"coverage": "checked",
"dependency": "required",
"disagreement": null,
"effective_at": "2026-09-03T11:59:00Z",
"evidence_id": "ev_3b9e1c7a5d2f8e61",
"evidence_version": "ev-1",
"freshness": {
"age_seconds": 2,
"stale": false,
"stale_after_seconds": null
},
"kind": "transaction_facts",
"observed_at": "2026-09-03T11:59:58Z",
"source": "chain_explorer",
"source_reference": "block:60000000",
"subject": {
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"type": "transaction"
},
"temporal_scope": "TRANSACTION_TIME"
},
{
"coverage": "checked",
"dependency": "required",
"disagreement": null,
"effective_at": "2026-09-03T11:59:00Z",
"evidence_id": "ev_5f0c3a1d9b2e7f40",
"evidence_version": "ev-1",
"freshness": {
"age_seconds": 2,
"stale": false,
"stale_after_seconds": null
},
"kind": "transaction_facts",
"observed_at": "2026-09-03T11:59:58Z",
"source": "chain_node",
"source_reference": "block:60000000",
"subject": {
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"type": "transaction"
},
"temporal_scope": "TRANSACTION_TIME"
},
{
"coverage": "checked_freshness_unknown",
"dependency": "required",
"disagreement": null,
"effective_at": null,
"evidence_id": "ev_8a4d2e6f1c9b3a75",
"evidence_version": "ev-1",
"freshness": {
"age_seconds": 0,
"stale": true,
"stale_after_seconds": null
},
"kind": "aml_risk",
"observed_at": "2026-09-03T12:00:00Z",
"source": "aml_provider",
"source_reference": "transaction_risk_score",
"subject": {
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"type": "transaction"
},
"temporal_scope": "CHECK_TIME"
},
{
"coverage": "checked",
"dependency": "required",
"disagreement": null,
"effective_at": null,
"evidence_id": "ev_c27f5b0e9d4a1863",
"evidence_version": "ev-1",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 172800
},
"kind": "sanctions_list",
"observed_at": "2026-09-03T12:00:00Z",
"source": "ofac",
"source_reference": "configured_address_index",
"subject": {
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"type": "transaction_addresses"
},
"temporal_scope": "LIST_PUBLICATION"
},
{
"coverage": "checked",
"dependency": "required",
"disagreement": null,
"effective_at": "2026-08-28T00:00:00Z",
"evidence_id": "ev_4e18a9d3b6c07f52",
"evidence_version": "ev-1",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"kind": "sanctions_list",
"observed_at": "2026-09-03T12:00:00Z",
"source": "eu",
"source_reference": "configured_address_index",
"subject": {
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"type": "transaction_addresses"
},
"temporal_scope": "LIST_PUBLICATION"
},
{
"coverage": "checked",
"dependency": "required",
"disagreement": null,
"effective_at": "2026-08-28T00:00:00Z",
"evidence_id": "ev_91d6f2a8c3e5b047",
"evidence_version": "ev-1",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"kind": "sanctions_list",
"observed_at": "2026-09-03T12:00:00Z",
"source": "uk",
"source_reference": "configured_address_index",
"subject": {
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"type": "transaction_addresses"
},
"temporal_scope": "LIST_PUBLICATION"
},
{
"coverage": "not_applicable",
"dependency": "not_applicable",
"disagreement": null,
"effective_at": null,
"evidence_id": "ev_6b03e7c1f5a92d48",
"evidence_version": "ev-1",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"kind": "sanctions_list",
"observed_at": null,
"source": "un",
"source_reference": "configured_address_index",
"subject": {
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"type": "transaction_addresses"
},
"temporal_scope": "LIST_PUBLICATION"
},
{
"coverage": "checked",
"dependency": "required",
"disagreement": null,
"effective_at": null,
"evidence_id": "ev_f0a5c8e2d7b41936",
"evidence_version": "ev-1",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"kind": "token_authenticity",
"observed_at": "2026-09-03T12:00:00Z",
"source": "token_registry",
"source_reference": "official",
"subject": {
"ref": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"type": "token"
},
"temporal_scope": "CHECK_TIME"
}
],
"finality_policy": "tron_solidified_19_confirmations",
"finalized": true,
"freshness": {
"checked_at": "2026-09-03T12:00:00Z",
"max_source_age_seconds": 2,
"risk_data_at": "2026-09-03T12:00:00Z",
"token_data_at": "2026-09-03T12:00:00Z",
"transaction_at": "2026-09-03T11:59:00Z"
},
"indirect_sanctions_exposure": false,
"integrity": {
"comparisons": {
"amount": {
"actual": "1250.000001",
"delta": "0",
"delta_raw": "0",
"expected": "1250.000001",
"result": "EXACT",
"tolerance": null
},
"network": {
"actual": "tron",
"expected": null,
"result": "NOT_EVALUATED"
},
"recipient": {
"actual": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"expected": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"result": "MATCH"
},
"sender": {
"actual": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"expected": null,
"result": "NOT_EVALUATED"
},
"token": {
"actual": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"expected": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"result": "MATCH"
}
},
"relevant_event_count": 1,
"selected_event_ref": "log:0",
"status": "MATCH"
},
"integrity_status": "MATCH",
"key_exposure": [],
"limitations": [],
"network": "tron",
"obligation": null,
"overall_state": "CLEAR",
"policy_version": "b2b-tx-2026-10.4",
"reasons": [
{
"category": "transaction",
"code": "TX_FACTS_VERIFIED",
"severity": "info"
},
{
"category": "transaction",
"code": "TX_FINALIZED",
"severity": "info"
},
{
"category": "risk",
"code": "AML_LOW",
"severity": "info"
},
{
"category": "sanctions",
"code": "NO_DIRECT_SANCTIONS_MATCH",
"severity": "info"
},
{
"category": "token",
"code": "TOKEN_OFFICIAL",
"severity": "info"
}
],
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"recipient_match": true,
"recommended_action": "CONFIRM_INTERNAL_STATE",
"request_id": "req-3f34a12f",
"required_confirmations": 19,
"result_final": true,
"retry_after_seconds": null,
"retryable": false,
"reuse": {
"first_seen_at": null,
"other_obligations": 0,
"prior_decisions": 0,
"status": "FIRST_SEEN"
},
"risk": {
"driver": null,
"driver_evidence_ids": [],
"status": "NO_MATERIAL_SIGNAL"
},
"risk_exposure": false,
"risk_final": true,
"risk_retry_after_seconds": null,
"risk_retryable": false,
"risk_status": "NO_MATERIAL_SIGNAL",
"sanctions_hit": false,
"schema_version": "0.3",
"selected_transfer_index": 0,
"sender": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"source_coverage": {
"risk_sources": {
"aml_provider": {
"checked_at": "2026-09-03T12:00:00Z",
"data_updated_at": null,
"error_code": null,
"retrieved_at": "2026-09-03T12:00:00Z",
"scope": "transaction_risk_score",
"stale_after_seconds": null,
"status": "checked_freshness_unknown"
}
},
"sanctions_sources": {
"eu": {
"checked_at": "2026-09-03T12:00:00Z",
"data_updated_at": "2026-08-28T00:00:00Z",
"error_code": null,
"retrieved_at": "2026-09-01T09:00:00Z",
"scope": "configured_address_index",
"stale_after_seconds": 3024000,
"status": "checked"
},
"ofac": {
"checked_at": "2026-09-03T12:00:00Z",
"data_updated_at": null,
"error_code": null,
"retrieved_at": "2026-09-03T06:00:00Z",
"scope": "configured_address_index",
"stale_after_seconds": 172800,
"status": "checked"
},
"uk": {
"checked_at": "2026-09-03T12:00:00Z",
"data_updated_at": "2026-08-28T00:00:00Z",
"error_code": null,
"retrieved_at": "2026-09-01T09:00:00Z",
"scope": "configured_address_index",
"stale_after_seconds": 3024000,
"status": "checked"
},
"un": {
"checked_at": null,
"data_updated_at": null,
"error_code": null,
"retrieved_at": null,
"scope": "configured_address_index",
"stale_after_seconds": null,
"status": "not_applicable"
}
},
"transaction_sources": {
"chain_explorer": {
"checked_at": "2026-09-03T12:00:00Z",
"data_updated_at": null,
"error_code": null,
"retrieved_at": "2026-09-03T11:59:58Z",
"scope": "transaction_facts",
"stale_after_seconds": null,
"status": "checked"
},
"chain_node": {
"checked_at": "2026-09-03T12:00:00Z",
"data_updated_at": null,
"error_code": null,
"retrieved_at": "2026-09-03T11:59:58Z",
"scope": "transaction_facts",
"stale_after_seconds": null,
"status": "checked"
}
},
"universal_clearance": false
},
"status_drivers": {
"action": "CUSTOMER_STATE_UNKNOWN",
"coverage": null,
"integrity": null,
"risk": null,
"transaction": "TX_FINALIZED"
},
"token_authenticity": "official",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_match": true,
"token_symbol": "USDT",
"trace_complete": null,
"transaction_category": "trc20_transfer",
"transaction_state": "confirmed",
"transaction_status": "CONFIRMED",
"transaction_type": "TriggerSmartContract",
"transfers": [
{
"amount": "1250.000001",
"asset_type": "trc20",
"decimals": 6,
"event_ref": "log:0",
"execution_status": "success",
"index": 0,
"raw_amount": "1250000001",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"sender": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_id": null,
"token_symbol": "USDT"
}
],
"transfers_truncated": false,
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"verification_final": true,
"versions": {
"contract": "0.3",
"decision": "b2b-tx-2026-10.4",
"evidence_schema": "ev-1",
"reason_codes": "rc-1",
"rules": {
"allocation": "alloc-v1",
"billing": "final_answers_only",
"exposure": "b2b-exp-v2",
"integrity": "int-v3",
"reuse": "reuse-v1",
"sanctions_freshness": "sf-v1"
}
},
"workflow_coverage": "complete",
"workflow_type": "PAYOUT"
},
"network": "tron",
"reason_codes": [
"TX_FACTS_VERIFIED",
"TX_FINALIZED",
"AML_LOW",
"NO_DIRECT_SANCTIONS_MATCH",
"TOKEN_OFFICIAL"
],
"request_id": "req-3f34a12f",
"risk_level": "low",
"state": "clear"
}
Authentication
One ChainZap account
Use Continue with ChainZap to sign in with the account you use in the app. From Settings → Developer API → Dashboard, an existing browser login continues without another sign-in. Your organization, API keys and API allowance stay separate from personal app credits. A previous Google portal login is linked using the verified Google account identifier, never by matching email addresses.
Ordinary sign-in needs no invitation code. Invitations are only for joining an existing organization. If Telegram opens a separate browser that has no ChainZap session, sign in there once with the same account. Link Google and Telegram in the app's account settings before switching between them.
Server API keys
Send X-API-Key over HTTPS on every request to the business API. Never place a key in a URL, browser storage, analytics, a support message or source control. A key grants access to one organization; a request cannot select another organization.
Signing in to the developer dashboard is separate from API keys. Live keys start with cz_live_; sandbox keys start with cz_test_.
Dashboard roles:
- Owner, admin and developer members create, rotate and revoke API keys.
- Owner, admin and billing members view payment history, buy plans and extra checks packages and manage the subscription.
- Viewer members only inspect usage and key metadata.
An API key cannot buy anything.
Key lifecycle
Give each integration its own key with a descriptive label. The full key is shown only once, on creation or rotation; lists show a prefix. Rotation revokes the old key and creates its replacement in one operation. Update your server's secret store right after rotation. To avoid an outage during a planned migration, create a separate key, move your integration to it and verify it, then revoke the previous key.
Access errors
401 invalid_api_key: the key is invalid or revoked.403 tenant_suspended: the organization is suspended.403 network_not_enabled: the requested network is not enabled for the organization.
Correct access first. Retrying the same request without a change does not help.
POST /v1/transaction/check
Request
This strict JSON request requires network and a 32-byte tx_hash. Unknown fields are rejected. Expected addresses are validated and normalized for the selected network. expected_amount is a nonnegative decimal string; JSON numbers and exponent notation are rejected. For optional network context and the short response, use POST /v1/check.
| Field | What to send |
|---|---|
network |
"tron", "eth" or "ton". Required. |
tx_hash |
64 hexadecimal digits with an optional 0x. TON also accepts canonical base64/base64url encoding of 32 bytes. |
expected_recipient |
Optional: the recipient address on the selected network. For TON, the wallet owner. |
expected_token |
Optional: the token contract on the selected network. For TON, the jetton master. |
expected_amount |
Optional: the amount as a string, for example "10.25". |
Address formats and exact comparison rules are in matching. Request bodies are limited to 4 KiB; a larger body is refused with 413 payload_too_large. Organizations on the pilot contract must send all three expected_* fields.
Send Content-Type: application/json, your server-side X-API-Key and an Idempotency-Key for the logical check operation. X-Request-ID links the request to your own operation log. The generated API reference lists the exact required fields, enums and response schemas.
Response
Read transaction_state independently from overall_state. The response includes confirmations, normalized transfers, the selected transfer, risk level, sanctions status, token authenticity, matching flags, coverage, freshness and 2 to 5 prioritized reasons. Transfer and exposure amounts are decimal strings. Handle nullable fields explicitly.
transfers_truncated=true means the transfer list was cut short. AMBIGUOUS_TRANSFER means several transfers satisfy your conditions. Both need attention. Do not treat a truncated list as complete and do not combine matching flags from different transfers.
Consume contract 0.3
Use verification_final and integrity_status for payment verification, then evaluate risk_status and recommended_action separately. Pending is NOT_EVALUATED, never MATCH. Final MATCH with risk_status: INSUFFICIENT confirms the payment comparison but requires MANUAL_REVIEW, not automatic credit or payout approval. Read risk_retryable independently from retryable. The response examples show these branches.
Billing
A final answer with coverage: complete uses one check from your quota, including a complete high-risk result: the transaction is confirmed past its finality policy, or it failed for good. A pending transaction, a transaction not found and a response with coverage: partial are not charged. Replaying the same idempotent operation never charges twice.
expected_token is a contract address (not a ticker); the legacy name expected_token_contract remains accepted. Send only one. The response carries schema_version: "0.3" and policy_version, the decision policy that produced the answer (store it with the answer), the three separate risk/sanctions flags, workflow_coverage and source_coverage. Read coverage before interpreting a clear result. Idempotency keys used before contract 0.2 return 409 idempotency_conflict; use a new key after handling the old result.
Check a wallet before you accept it or pay it
POST /v1/wallet/check screens one address the same way POST /v1/check screens one transaction: same key, same quota, same idempotency rules, same shape of answer. Send an address, receive a state, a coverage level and reason codes, and decide in your own workflow whether the counterparty needs a closer look.
Request
| Field | What to send |
|---|---|
address |
Required. An Ethereum address (0x and 40 hex digits), a TRON address (T and 33 base58 characters) or a TON address (48-character friendly form or workchain:hash). |
network |
Optional: "tron", "eth" or "ton". When omitted, the network is read from the address format. When sent, it must agree with the format; a mismatch is 422 invalid_tron_address, invalid_eth_address or invalid_ton_address. |
The three formats cannot be confused with each other, so a wallet check never answers NETWORK_REQUIRED or NETWORK_AMBIGUOUS. A string that matches none of them is 422 invalid_address. Unknown fields are rejected and the body is limited to 4 KiB. Send Content-Type: application/json, your server-side X-API-Key and an Idempotency-Key for the logical operation; X-Request-ID links the request to your own log.
curl --include --max-time 35 'https://api.chainzap.io/v1/wallet/check' \
-H 'Content-Type: application/json' \
-H 'X-API-Key: cz_live_000000000000.fictional_example_only' \
-H 'Idempotency-Key: onboarding-4711-wallet-1' \
-H 'X-Request-ID: onboarding-4711-attempt-1' \
--data '{"address":"TJRabPrwbZy45sbavfcjinPJC18kjpRTv8"}'
The address in the example is a public sample address, not a payment instruction. The response echoes address in its canonical spelling: Ethereum in lower case, TON as workchain:hash, TRON unchanged.
Response
Read the top level first, then details.
| Field | Meaning |
|---|---|
state |
clear, review, high_risk or limited_data. A screening result, never an instruction to pay or to refuse. |
coverage |
complete when every applicable module was fully screened, otherwise partial. A clear state is only ever returned with complete coverage. |
reason_codes |
Stable strings, ordered by severity, at most ten. The same codes appear as objects with category and severity in details.reasons. |
environment |
live or sandbox. |
details explains where the state came from:
overall_stateanddata_coverage: the upper-case state and the engine's own coverage word,FULL,PARTIALorINSUFFICIENT.modules: seven rows in a fixed order,sanctions_aml,wallet_behaviour,token_authenticity,contract_controls,address_security,counterparties_services,flows_connections. Each row has astatus(RISK_DETECTED,NO_MATCHES_FOUND,PARTIALLY_CHECKED,INSUFFICIENT_DATA,NOT_SUPPORTED,NOT_CHECKED) and asource_coverage(complete,partial,none,not_applicable). A module that was not screened says so; it is never reported as clean.sanctions:direct_matchagainst the configured OFAC, EU, UK and UN indexes (nullwhen no index was screened), the listingauthorities, whether the listing isattributed, andindirect_exposurereported by the AML provider (nullwhen it did not run).address_security: public denylist status and category,provider_flagged(whether the address-security provider flagged the address;nullwhen it did not answer or its rights do not let ChainZap show it), and whether the stablecoin issuer has frozen the address. The provider's own labels are never returned; the deprecatedprovider_flagsis["PROVIDER_SECURITY_FLAG"]whenprovider_flaggedis true and empty otherwise.behaviour: whether the address is a contract, the transaction count and whether it was capped, the wallet age, first and last activity, and the number of counterparties.counterpartiesandtoken_authenticity: how many counterparties were screened, unverified or flagged, and how many held tokens are official, fake, suspicious or unknown.freshnessandsource_coverage: when the check ran, whether the analysis came from the analysis cache (5 minutes on Ethereum, 30 minutes on TRON and TON; the AML provider's answer is reused for up to 24 hours), the oldest source age, and one observation per source with the same status vocabulary as the transaction check. Sources are named by role:ofac,eu_sanctions,uk_sanctions,un_sanctions,denylist,issuer_restrictions,aml_provider,address_security_provider,onchain,chain_explorer,chain_node,graph_risk.limitations:analysis_from_cache,transaction_sample_capped,aml_provider_unavailable,aml_provider_skipped_dominant_local_hit,counterparty_attribution_partial,network_assumed_eth,address_security_provider_withheld,sandbox_partial_fixture.
Every wallet reason code is listed with its meaning in reason codes.
What a wallet check is not
There is no numeric score anywhere in the response, by design. A number invites a threshold, and no threshold is honest across three networks with different sources. The response tells you what was found, what was screened and what could not be screened. It is not a compliance certificate and it does not know the internal rules of any exchange or bank. Treat clear as "nothing critical in the screened sources", review as "look before you proceed", high_risk as "a critical finding needs resolving", and limited_data as "we could not tell".
Billing
A wallet check uses one check from your quota when it produces a state: clear, review or high_risk, with complete or partial coverage. limited_data is free, as are errors, timeouts and idempotent replays. This differs from the transaction check, which is charged only with complete coverage: a wallet screen often reaches a firm verdict while one counterparty in fifty stays unattributed, and the paid sources have already answered. Sandbox keys never use paid checks.
Time budget and retries
A cold wallet check reads several providers and has a server budget of 30 seconds; use a client deadline of about 35 seconds. If the server answers 504 request_timeout, retry with the same body and the same Idempotency-Key: the analysis keeps running to completion on the server and lands in the shared cache, so the retry is usually answered at once and carries freshness.served_from_analysis_cache: true. The general retry rules apply unchanged.
Idempotency across kinds
Idempotency keys are shared per organization and environment across all check endpoints. Reusing a transaction's key for a wallet body, or a wallet's key for another address, answers 409 idempotency_conflict. One logical operation, one key.
Server examples
import os, requests
response = requests.post("https://api.chainzap.io/v1/wallet/check", timeout=35,
headers={"X-API-Key": os.environ["CHAINZAP_API_KEY"],
"Idempotency-Key": os.environ["CHECK_ID"]},
json={"address": os.environ["WALLET_ADDRESS"]})
result = response.json()
response.raise_for_status()
if result["state"] != "clear":
print(result["state"], result["reason_codes"])
const response = await fetch("https://api.chainzap.io/v1/wallet/check", {
method: "POST", signal: AbortSignal.timeout(35000),
headers: {"Content-Type": "application/json", "X-API-Key": process.env.CHAINZAP_API_KEY!,
"Idempotency-Key": process.env.CHECK_ID!},
body: JSON.stringify({address: process.env.WALLET_ADDRESS})
});
const result = await response.json();
if (!response.ok) throw new Error(result.error.code);
if (result.state !== "clear") console.info(result.state, result.reason_codes);
Deterministic response example
This is an illustrative fixture, not a live observation. Expand the complete JSON below.
View full JSON response
{
"address": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"coverage": "complete",
"details": {
"address_security": {
"denylist_category": null,
"denylisted": false,
"issuer_blocked": false,
"issuer_blocked_symbols": [],
"provider_flagged": false,
"provider_flags": []
},
"behaviour": {
"contract_verified": null,
"counterparties_count": 37,
"first_activity_at": "2024-09-20T10:15:00Z",
"is_contract": false,
"last_activity_at": "2026-09-19T08:02:11Z",
"transaction_count": 412,
"transaction_count_limited": false,
"wallet_age_days": 731
},
"counterparties": {
"flagged": 0,
"screened": 37,
"unverified": 0
},
"coverage_scope": "supported_deep_sources",
"data_coverage": "FULL",
"evidence": {
"live": true,
"source": "live"
},
"freshness": {
"analyzed_at": "2026-09-21T08:59:58Z",
"checked_at": "2026-09-21T09:00:00Z",
"oldest_source_age_seconds": 2,
"served_from_analysis_cache": false
},
"limitations": [],
"modules": [
{
"key": "sanctions_aml",
"source_coverage": "complete",
"status": "NO_MATCHES_FOUND"
},
{
"key": "wallet_behaviour",
"source_coverage": "complete",
"status": "NO_MATCHES_FOUND"
},
{
"key": "token_authenticity",
"source_coverage": "complete",
"status": "NO_MATCHES_FOUND"
},
{
"key": "contract_controls",
"source_coverage": "complete",
"status": "NO_MATCHES_FOUND"
},
{
"key": "address_security",
"source_coverage": "complete",
"status": "NO_MATCHES_FOUND"
},
{
"key": "counterparties_services",
"source_coverage": "complete",
"status": "NO_MATCHES_FOUND"
},
{
"key": "flows_connections",
"source_coverage": "complete",
"status": "NO_MATCHES_FOUND"
}
],
"overall_state": "CLEAR",
"reasons": [
{
"category": "sanctions",
"code": "NO_DIRECT_SANCTIONS_MATCH",
"severity": "info"
},
{
"category": "risk",
"code": "AML_LOW",
"severity": "info"
},
{
"category": "address",
"code": "NO_ADDRESS_SECURITY_FLAGS",
"severity": "info"
},
{
"category": "behaviour",
"code": "NO_BEHAVIOUR_FLAGS",
"severity": "info"
}
],
"sanctions": {
"attributed": false,
"authorities": [],
"direct_match": false,
"exposure_source": "aml_provider",
"indirect_exposure": false
},
"schema_version": "0.1",
"source_coverage": {
"ofac": {
"checked_at": "2026-09-21T09:00:00Z",
"data_updated_at": "2026-09-20T18:00:00Z",
"error_code": null,
"retrieved_at": "2026-09-21T09:00:00Z",
"scope": "sanctions_aml",
"stale_after_seconds": 172800,
"status": "checked"
}
},
"token_authenticity": {
"fake": 0,
"official": 3,
"suspicious": 0,
"total": 3,
"unknown": 0
},
"universal_clearance": false
},
"environment": "live",
"network": "tron",
"reason_codes": [
"NO_DIRECT_SANCTIONS_MATCH",
"AML_LOW",
"NO_ADDRESS_SECURITY_FLAGS",
"NO_BEHAVIOUR_FLAGS"
],
"request_id": "8a7f1c2e9d3b4f5a8c6d7e9f0a1b2c3d",
"state": "clear"
}
Match a transfer to a payment
Use the expected_* fields to verify the recipient, token contract and amount of a specific payment. Send all three fields or only the comparisons you need.
The following comparisons apply after chain finality. While transaction_status: PENDING, integrity and every requested comparison are NOT_EVALUATED, and all match flags are null, even when an observed transfer has the expected values. A final MATCH verifies payment details independently of KYT; insufficient risk still requires MANUAL_REVIEW.
One transfer, three comparisons
A transaction can contain several transfers. ChainZap first looks for a transfer that satisfies every supplied condition. If none does, it selects the transfer with the most matches. Ties are resolved consistently using the transfer index.
recipient_match, token_match and amount_match all describe that same transfer. If several transfers satisfy every condition, the response includes AMBIGUOUS_TRANSFER. A transfer that did not execute, such as one in a reverted transaction, is never a match: its three fields are null, and a failed transaction in which nothing executed is NOT_EVALUATED, never LIMITED_DATA for missing transfer rows.
Contract 0.3 states the comparison in full in integrity: status (see status axes), selected_event_ref, relevant_event_count (executed transfers to the expected recipient in the expected token) and comparisons with the expected and actual value and a result for recipient, sender, token, amount and network. The amount result is EXACT, WITHIN_TOLERANCE, UNDERPAID, OVERPAID, NOT_EVALUATED or INSUFFICIENT, with the signed delta and delta_raw.
| Relevant transfers | Answer |
|---|---|
| One, amount matches | MATCH. |
| One, amount differs | MISMATCH with UNDERPAID or OVERPAID. |
| Several, exactly one amount matches | MATCH and ADDITIONAL_RELEVANT_TRANSFERS: the transaction may pay twice. |
| Several of one asset, none matches but together they make the amount | MATCH and SPLIT_WITHIN_TX. Movements of different assets never add up. |
| Several that fit equally | AMBIGUOUS; nothing is allocated. |
| Result | Meaning |
|---|---|
true |
The value matches the one you supplied. |
false |
The value could be checked but does not match. |
null |
You did not request this comparison, or there was not enough data to make it. |
How values are compared
If you provide an expected value but its transfer data is unavailable, the corresponding match field is null, coverage is partial, and the reasons include EXPECTED_DATA_UNAVAILABLE. Missing token decimals, for example, do not prove an amount mismatch. Do not treat null as a successful match.
Addresses are validated and normalized for the selected network:
| Network | Accepted addresses and comparison |
|---|---|
tron |
Base58Check with a valid checksum. Compare the TRON address exactly. |
eth |
0x followed by 40 hexadecimal digits. Uniform lowercase or uppercase is accepted; mixed case must pass EIP-55. Comparisons use lowercase addresses. |
ton |
Raw workchain:account or a friendly address with a valid checksum. Only workchains 0 and -1 are accepted; test-only addresses are rejected. Bounceable and non-bounceable forms normalize to the same account. |
For TON, expected_recipient is the wallet owner and expected_token is the jetton master, not the jetton wallet.
Tokens are compared by exact contract, never by name or symbol; the same symbol does not prove the same token. Amounts are converted from decimal strings to raw integer units using the known token decimals and compared exactly; no floating-point tolerance is applied. To accept a small difference, send amount_tolerance: an absolute amount in token units, symmetric, 0 by default. A difference within it is WITHIN_TOLERANCE and adds AMOUNT_WITHIN_TOLERANCE; a tolerance with more decimal places than the token answers 422 invalid_amount_tolerance. expected_sender compares the sending address the same way as the recipient. Digits beyond the token's decimals are accepted when they are zeros: "10.0000000" equals "10" for a 6-decimal token. A nonzero digit beyond them returns 422 invalid_expected_amount.
Mismatch example
If you expect "10.000001" but the selected transfer contains "10", the response includes amount_match=false and EXPECTED_AMOUNT_MISMATCH.
A different recipient produces EXPECTED_RECIPIENT_MISMATCH; a different token contract produces EXPECTED_TOKEN_MISMATCH. A matching amount does not prove that the recipient and token also match. Before accepting a payment, check every required comparison, the transaction state and the overall assessment.
Pilot contract
An organization on the design-partner pilot contract must send all three fields on every check: a check without expected_recipient, expected_token or expected_amount is refused with 422 expected_fields_required, and an expected_token other than official USDT on TRON with 422 token_not_enabled. Refusals happen before the check is accepted: nothing is charged or stored, and sandbox keys follow the same rules.
Network context
These comparisons work with both check endpoints. When you already know the payment network, supply it explicitly. The API then validates the expected addresses against that network and never switches to another chain. See network discovery for requests without network.
Obligations, attempts and allocations
A single check answers whether one transaction pays what you expect. The obligation ledger answers whether a business obligation, a payout or a deposit you are owed, was paid: once, in full, by which transactions, and whether the same payment is presented for something else. It keeps your instructions, your execution attempts, the payment events ChainZap verified and how they were allocated, and never rewrites any of them.
The ledger is switched on per deployment. While it is off, a check with any ledger field and every ledger endpoint answer 403 ledger_not_enabled.
The model
| Record | What it is |
|---|---|
| Obligation | One business reference (external_reference, unique per organization and environment) with a workflow_type (PAYOUT, DEPOSIT, INVOICE, REFUND, SETTLEMENT, OTHER) and a direction (OUTGOING, INCOMING). |
| Instruction version | What was owed: network, recipient, optional sender, token contract, amount and amount_tolerance, with instruction_effective_at and approval_reference. Append-only. |
| Execution attempt | One try at paying it (attempt_reference), with channel, provider_reference, status and optional amount and tx_hash. A retry or a switch of payment provider is a new attempt. |
| Payment event | One verified on-chain movement, identified by network, transaction and event_ref (for example log:3). One transaction can hold several events. |
| Allocation | How much of one event settles one obligation, with its status (MATCHED, CUSTOMER_DECLARED, UNKNOWN, DISPUTED) and source (CHAINZAP_MATCH, CUSTOMER, BATCH; OPERATOR is reserved). Reversed, never deleted. |
| Decision | ChainZap's answer to one check, kept as it was given. See decisions. |
external_reference, attempt_reference and approval_reference are up to 128 printable ASCII characters. Do not put personal data in them.
Check against an obligation
Add the obligation's reference to an ordinary transaction check:
{
"tx_hash": "…",
"network": "tron",
"external_reference": "payout-2026-10-0001",
"attempt_reference": "attempt-1",
"direction": "OUTGOING",
"workflow_type": "PAYOUT",
"expected_recipient": "T…",
"expected_token": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"expected_amount": "100.00"
}
The first check of a new reference records the obligation and its instruction (version 1, or the instruction_version you send). Later checks may send only the reference: the recorded instruction is what the transaction is compared with. The answer adds an obligation block (status, expected_amount, allocated_amount, residual_amount, attempts, events, pending_events) and a reuse block.
When the transaction matches, or pays the right recipient and token a different amount, its event is allocated to the obligation. Only final, executed events are allocated; a pending one is counted in pending_events and never closes the obligation. When several movements fit equally (integrity_status: AMBIGUOUS), each is linked to the obligation as UNKNOWN with nothing allocated, until you declare which one paid. A check that omits direction takes the obligation's recorded one, or else infers it from workflow_type (PAYOUT and REFUND are outgoing, DEPOSIT and INVOICE incoming); a payment whose direction stays unknown is never PROCEED.
Obligation status |
Meaning |
|---|---|
OPEN |
Nothing allocated yet. |
PARTIALLY_ALLOCATED |
Less than the amount, minus the tolerance, is allocated. residual_amount is what remains. |
ALLOCATED |
The amount is covered within the tolerance. |
OVER_ALLOCATED |
More than the amount plus the tolerance is allocated. When two or more transactions did that, the answer adds DUPLICATE_EXECUTION. |
CANCELLED |
Reserved for a cancelled obligation; the API does not set it yet. |
Instructions never change in place
An instruction version is immutable. Sending the same version with different terms is refused with 409 instruction_conflict; sending different terms without a version is refused with 409 instruction_version_required. A changed instruction is a new version, recorded with POST /v1/obligations and a higher instruction_version; earlier versions stay on record and a check can name the version it was paid under. A version you never recorded is not reconstructed: the check answers integrity_status: INSUFFICIENT with INSTRUCTION_UNAVAILABLE. A payment in a block before instruction_effective_at adds INSTRUCTION_NOT_EFFECTIVE.
Record obligations and attempts up front
| Endpoint | Purpose |
|---|---|
POST /v1/obligations |
Record an obligation, or a new version of its instruction. |
POST /v1/obligations/lookup |
The obligation with its instructions, attempts, allocations and decisions. Send {"external_reference": "…"} in the body: a reference never travels in a URL, where proxies log it. |
POST /v1/obligations/attempts |
Record an attempt or a new status of one (CREATED, SUBMITTED, BROADCAST, TIMEOUT, FAILED, CANCELLED, PROVIDER_CONFIRMED, UNKNOWN). Every status change is kept in status_history. The same attempt_reference with another channel, provider_reference, amount or transaction is refused with 409 attempt_conflict, and so is a check that names it with another tx_hash: a retry or a provider switch is a new attempt. |
An attempt is not an execution. execution_confirmed turns true only when a payment event of its transaction is allocated to the obligation; a TIMEOUT attempt followed by a successful retry leaves two attempts and one execution. When attempts carry an amount, a check made with that attempt_reference compares the transaction with the attempt's amount, so a payout split into legs matches leg by leg.
Shared payments and reuse
One payment can settle several obligations, and one obligation can be paid by several payments.
- Several obligations, one payment. ChainZap never splits a payment on its own. Declare the shares with
POST /v1/allocations(network,tx_hash,event_ref,allocations: [{external_reference, amount}], and an optionalownerthat stamps any earlier allocation the declaration replaces). The event exists once a check naming an obligation recorded it with complete coverage (404 payment_event_not_foundotherwise); it must have executed and be final (409 payment_event_not_settled), be in the obligation's token (409 allocation_token_mismatch), and the shares cannot exceed it (409 allocation_exceeds_event). A check of one share then compares that share, not the whole payment, with what the obligation is owed. - One obligation, several payments. Each check under the same reference adds its event;
residual_amountfalls until the obligation isALLOCATED. - Reversal.
POST /v1/allocations/{allocation_id}/reversalwith areason(CUSTOMER_CORRECTION,DISPUTED,DUPLICATE_RECORD,OTHER) stamps the allocation as reversed, andDISPUTEDmarks itDISPUTED. It stays on record, and a later check never restores it; only a declaration can.
reuse.status says what the ledger already knows about the payment event:
| Status | Meaning |
|---|---|
FIRST_SEEN |
Nothing about this transaction is on record. |
REPEAT_CHECK |
It was checked before, but nothing claims it for an obligation. Asking again is normal and never a finding. |
SAME_OBLIGATION |
It was already matched to this obligation. A recheck does not allocate it twice. |
DECLARED_SHARED |
You declared that it settles several obligations, this one included. |
OTHER_OBLIGATION |
It already settles a different obligation: TX_REUSED_ACROSS_OBLIGATIONS, REVIEW, and nothing is allocated to this one. |
An idempotent replay (the same Idempotency-Key and body) returns the stored answer and is not a reuse.
Incoming payments
For a deposit, send direction: "INCOMING" and tell ChainZap what your system already did with it in customer_context: credit_status (NOT_CREDITED, CREDITED, PARTIALLY_CREDITED, UNKNOWN) and allocation_status (NOT_ALLOCATED, PARTIALLY_ALLOCATED, ALLOCATED, UNKNOWN), how far your books already applied it. ChainZap cannot see your books: without NOT_CREDITED a clean deposit is CONFIRM_INTERNAL_STATE, an UNKNOWN allocation is too, and a payment credited or applied even in part gives REVIEW with ALREADY_CREDITED. The same obligation, allocation and reuse rules apply to deposits and payouts.
Retention
Raw references, addresses and transaction hashes are kept for 90 days and then replaced by keyed digests; owners are removed. Amounts, tokens, statuses and versions remain, so the totals stay right. After that the ledger still recognises a reused payment and a repeated reference by digest, and the API returns redacted: true where a raw value is gone. A digest of an amount and a block time is pseudonymous, not anonymous.
Batches
A batch checks a file of payments, 50 to 200 rows, on the same engine as a single check: every row gets the same answer, reasons and ledger effects it would get alone. The file is validated and priced first; nothing runs and nothing is charged until you confirm. Batches use the obligation ledger, and answer 403 batch_not_enabled while it is off.
You can upload, run and export a batch in the developer dashboard on the Batches page, or through the API below. Both use the same service and limits.
The file
A CSV in UTF-8 (a byte order mark is fine), comma- or semicolon-separated, with a header row. Up to 200 rows and 256 KiB. One row is one payment of one obligation.
| Column | Required | Meaning |
|---|---|---|
external_reference |
yes | The obligation the row is about. |
network |
yes, or as a default | tron, eth or ton (trx, trc20, ethereum, erc20 are read too). |
tx_hash |
no | The transaction to check. Without it the row only records the obligation, which then appears among the open obligations. |
expected_recipient, expected_token, expected_amount |
the first time a reference is seen | What is owed. expected_token is a contract or a registry symbol such as USDT. |
amount_tolerance, expected_sender |
no | As in a single check. |
direction, workflow_type |
no | OUTGOING or INCOMING; PAYOUT, DEPOSIT, INVOICE, REFUND, SETTLEMENT, OTHER. |
instruction_version, instruction_effective_at, approval_reference |
no | The instruction the row was paid under. |
attempt_reference, attempt_status, channel, provider_reference, attempt_amount |
no | The execution attempt behind the row. |
allocated_amount |
no | Your share of a payment that settles several obligations. |
Common header names are recognised: order_id, payout_id, invoice_id, reference for the reference; txid, hash, transaction_hash for the hash; to, recipient, address, wallet for the recipient; token, contract, asset, currency for the token; amount, tolerance, from, sender, chain, attempt, provider, status. Unknown columns are ignored and listed in preflight.ignored_columns. Query parameters network, direction and workflow_type set defaults for rows that leave them empty. Download a template from the dashboard.
Upload and preflight
curl --max-time 30 'https://api.chainzap.io/v1/batches?network=tron' \
-H 'X-API-Key: YOUR_SERVER_API_KEY' -H 'Content-Type: text/csv' \
-H 'Idempotency-Key: payouts-2026-10-05' --data-binary @payouts.csv
201 returns the batch in PREFLIGHTED with:
preflight:rows,checks,obligations_only,invalidandduplicates, witherrorsandwarningscounted by code. A row with an error is skipped (SKIPPED_INVALID) and the error names the field, for exampleinvalid_tron_addressorunknown_token_symbol; an identical repeated row is skipped as a duplicate. When rows give one reference different terms, the first stands and the later ones are refused (conflicting_rows_for_obligation). Warnings do not skip a row:tx_shared_across_references(one transaction under several references withoutallocated_amount),declared_shared_payment,several_transactions_for_obligation, andtx_seen_for_other_obligationwhen the ledger already ties the transaction to another obligation.estimate: an upper bound, never a promise.distinct_transactions,billable_checks_at_most,provider_calls_at_most,provider_usd_at_most(priced as if nothing were cached),quota_availableandquota_sufficient.
A file that is not UTF-8, is empty, has no header or data rows, or has a malformed row answers 422 invalid_csv; a header without an external_reference column or with a repeated column answers 422 invalid_csv_header; more than 200 rows answer 413 batch_too_large. An Idempotency-Key names one file: the same key with the same file returns the same batch, with another file 409 idempotency_conflict. An organization runs at most two batches at a time; starting a third answers 429 batch_limit_reached (uploading and preflighting cost nothing and are not limited this way).
Run
POST /v1/batches/{batch_id}/execute with {"confirm": true} queues the batch; without confirm it answers 422 confirmation_required. If the quota cannot cover every distinct transaction it answers 409 insufficient_quota; send "allow_partial": true to start anyway.
Rows are checked by a worker, never faster than half of your organization's rate limit, so your own traffic keeps working; batches of all organizations take turns, a slice at a time. Rows of one transaction run in file order. Each distinct transaction is charged once per batch: once a row of it produced a charged answer, later rows of the same transaction are checked against their own obligation for free (a row that was refused charges nothing, so the next one is charged). If the quota or the daily ceiling of unbilled checks runs out, the batch pauses (PAUSED, with pause_reason quota_exceeded or daily_unbilled_ceiling); execute it again to resume.
Batch status |
Meaning |
|---|---|
PREFLIGHTED |
Validated and priced, waiting for your confirmation. |
QUEUED, RUNNING |
Being checked. |
PAUSED |
Stopped by quota or the unbilled ceiling; resume with execute. |
CANCELLING, CANCELLED |
Stopped by you; rows already checked keep their answers. |
COMPLETED |
Every row has an answer or an error. |
FAILED |
The organization was suspended while the batch ran. |
Row state |
Meaning |
|---|---|
PENDING, CLAIMED |
Waiting, or being checked. |
DONE |
Payment verification is final (verification_final: true), or the row only recorded an obligation. The risk part can still have a temporary gap: such a row keeps risk_retryable: true, usually with risk_status: INSUFFICIENT, and retry does not run it again. |
RETRYABLE |
Verification is not final yet (pending, not found, a temporary chain-source gap) or the check failed with a 5xx. |
FAILED |
The check was refused with a 4xx; fix the row and upload it again. |
SKIPPED_INVALID, SKIPPED_DUPLICATE, CANCELLED |
Not checked. |
POST /v1/batches/{batch_id}/retry runs again only the RETRYABLE rows of a completed or paused batch, up to five attempts per row; 409 nothing_to_retry when there are none. POST /v1/batches/{batch_id}/cancel stops it.
A row whose only gap is risk (a KYT outage) is DONE, not RETRYABLE: read its risk_retryable and risk_retry_after_seconds, and check that transaction again with a new Idempotency-Key when you need the risk part (see retries).
Results
GET /v1/batcheslists your recent batches;GET /v1/batches/{batch_id}returns one withprogressand, once it ran,summary.GET /v1/batches/{batch_id}/rows?after=0&limit=100pages through the rows with their compact answers (the four statuses,recommended_action, the amount result and delta, the reuse and obligation status, reason codes,decision_id). Filter withstate=orreview=true.GET /v1/batches/{batch_id}/export.csvreturns every row and its answer. Cells that a spreadsheet would read as a formula are prefixed with', and every cell is quoted.
summary counts rows by state and by overall_state, gives the distribution of each status axis and of recommended_action, the number of rows with analyst_review_required, the errors, and the cost: usd_total, usd_per_transaction and usd_per_exception (any answer other than CLEAR), with cost_complete. obligations lists the open ones with what is allocated and what remains.
analyst_review_required marks a row a person must look at: a MANUAL_REVIEW or HOLD_AND_ESCALATE recommendation. A row whose answer is not final yet (RECHECK_LATER) asks for a retry, not for a person.
Sandbox
Sandbox keys run batches against sandbox fixtures and spend the sandbox allowance; the same file runs unchanged on a live key. Raw row values are kept for 90 days, like the ledger's, and then removed; counts, statuses and digests remain.
Legal pack and delivery scope
The Business Terms, Pilot Agreement, Pilot Data Annex and Privacy Policy are available from the portal legal links. Pre-incorporation templates still require the contracting and commercial fields before signature. The initial pilot profile is official USDT/TRON.
There is no dedicated integrity-only switch: checks invoke the risk layer and show insufficient/degraded coverage when required risk evidence is missing. The portal presents compact rows, review flags, known residuals and CSV; detailed decision evidence and reversal/correction operations use the API. A completed batch is a decision-time snapshot and does not automatically refresh after later ledger corrections. DONE means processed, not paid or a customer-confirmed outcome.
Escrow deals
An escrow deal holds USDT on TRON in its own contract. The money moves only when someone with the right acts: the buyer releases it, the seller refunds it, a party claims it after a deadline the other side let pass, both parties propose the same split in a dispute, or a resolver named before funding decides one. Your platform drafts the deal and shows it; the buyer and the seller sign the terms and move the funds with their own wallets. ChainZap creates the contract once both have signed and watches the deadlines, but it never holds the parties' keys, is never a resolver and cannot move the money.
Escrow deals are a closed pilot. Until your organization is enabled, every call answers 403 escrow_not_enabled. The sandbox runs on the TRON Nile test network with a test token that has no value.
Two modes
Every deal can be disputed. The only choice is whether a resolver may also decide a dispute.
| No resolver (default) | With an external resolver | |
|---|---|---|
| Request | resolver_enabled omitted or false |
"resolver_enabled": true, resolver_id, resolver_fee, timeline.resolve_period_seconds |
| Resolver | none: the contract records the zero address, no fee and no window | an external resolver your platform registered, fixed with its fee and window in the signed terms before funding; it can never be named or changed later |
| A dispute settles | when both parties propose the same split | the same, or by the resolver's ruling within its window |
| No settlement | deadlock: the funds stay locked until the parties agree, the buyer releases or the seller refunds | the same, once the resolver's window has passed |
| Resolver fee | none | paid from the escrow only if the resolver decides the dispute |
Start without a resolver: it suits deliveries that pass or fail an objective check, and both parties can always end a dispute themselves.
What the contract allows
- Each deal is its own contract, created by an immutable factory: no owner, no upgrade, no pause and no admin key.
- Money moves only on a party's own act, or on the resolver's ruling within its window:
- the buyer releases (
release) and the seller refunds (refund) at any time after funding until the deal settles, a dispute included; - the buyer claims a refund (
claimRefund) once the delivery deadline passed without delivery; the seller claims the payment (claimRelease) once inspection ended without acceptance or dispute; - in a dispute, the deal settles the moment both parties' proposals match (
proposeSettlement), or when the resolver rules (resolve).
- the buyer releases (
- No timer decides a dispute, and a deadline moves nothing by itself: it only opens a claim for one party.
- Anyone, ChainZap included, may only confirm the funding (
confirmFunding), close an unfunded deal after its deadline (expire), pay out what is already credited to its fixed recipient (withdraw) and credit stray tokens to the buyer (sweepExcess). All of these work directly on the contract, without ChainZap. - Payouts go only to the buyer, the seller, the fee recipient fixed in the factory and, after its ruling, the named resolver.
Lifecycle
| Step | Who | Result |
|---|---|---|
| Draft | your platform, POST /v1/escrow-deals |
status: DRAFT, the participant link |
| Consent | buyer and seller, each with their wallet | the text both sign commits to every term |
| Agreement | automatic once both signed | AGREED, then CREATING while the contract is deployed |
| Funding | buyer: an ordinary token transfer of the amount to the escrow; then anyone calls confirmFunding |
state: FUNDED |
| Delivery | seller: markDelivered with an evidence hash |
DELIVERED, the inspection period starts |
| Acceptance | buyer: release, or dispute within the inspection period |
RELEASED or DISPUTED |
| Silence | buyer: claimRefund after the delivery deadline; seller: claimRelease after inspection |
REFUNDED or RELEASED |
| Dispute | both parties: proposeSettlement; the resolver, if any: resolve within its window |
RELEASED, REFUNDED or SPLIT |
status is the off-chain draft state (DRAFT, AGREED, CREATING, ON_CHAIN, CANCELLED, AGREEMENT_EXPIRED, CREATION_BLOCKED); once on chain, state is the contract's own (AWAITING_FUNDS, FUNDED, DELIVERED, DISPUTED, RELEASED, REFUNDED, SPLIT, EXPIRED). Deadlock is not a contract state: it is a dispute no resolver can decide any more, reported as settlement.deadlocked. The chain is the source of truth: the API reports what it read from solidified blocks and marks contract.out_of_sync when it cannot confirm the latest state.
Funding
Funding is an ordinary transfer of the deal's token to the escrow address, with no allowance and no transferFrom. Once the escrow holds at least the amount, anyone may call confirmFunding before the funding deadline; ChainZap does it as soon as it sees the balance. Until then funding reports what the escrow has received and what remaining amount is missing, as last read from the chain.
- Less than the amount. The deal stays
AWAITING_FUNDS; send the rest before the funding deadline.confirmFundingrefuses an escrow that holds less. - More than the amount, or a second transfer. After funding, the excess is credited to the buyer (
sweepExcess, eventescrow_deal.excess_credited) and withdrawn like any payout. It is never locked in the deal and never goes to ChainZap. - Too late. After the funding deadline the deal can only be closed (
expire, stateEXPIRED); anything sent to it is credited to the buyer and can be withdrawn. - From another address. Only the escrow's balance counts, so a transfer from any address funds the deal, and every refund or excess goes to the buyer's address in the terms, not to the sender.
The deal page sends exactly the remaining amount to the escrow it read from the factory, and refuses any other recipient, token or value.
Deadlines and claims
| State | Deadline | What it opens | Who must act |
|---|---|---|---|
AWAITING_FUNDS |
funding deadline | the deal closes unfunded (EXPIRED) |
anyone; ChainZap does |
FUNDED |
delivery period after funding | a full refund to the buyer | the buyer (claimRefund) |
DELIVERED |
inspection period after delivery | the payment to the seller, less the fee | the seller (claimRelease) |
DISPUTED |
the resolver's window, with a resolver | nothing: deadlock until the parties settle | the parties |
Deadlines use block time. An action is accepted only before its deadline and a claim only from the deadline on, so the two never overlap. A claim is not automatic: until the party makes it, the other side can still act, for example the buyer can still release after the delivery deadline. timeline.if_nobody_acts in every response says what the current deadline opens: at, outcome (EXPIRED, REFUNDED, RELEASED or DEADLOCK) and claim_by (BUYER, SELLER, ANYONE, or null when nothing opens).
Live deals give the buyer at least 72 hours to inspect (422 inspection_period_below_policy otherwise). Because silence lets the seller claim the payment, ChainZap reminds the buyer by Telegram right after delivery, half way through inspection, 12 hours and 1 hour before it ends; the seller is reminded 24 and 2 hours before the delivery deadline, and each party is told when its claim opens.
Disputes, proposals and deadlock
The buyer may open a dispute (dispute, with an evidence hash) only during inspection. From then on the seller cannot claim the payment, and no timer decides the outcome.
- Proposals. Each party proposes
buyer_amount, what the buyer gets back out of the amount:0sends everything to the seller (less the fee), the full amount refunds the buyer, anything between is a split. Either party may change its proposal at any time; the deal settles the moment both match (settlement_reason: MUTUAL_SETTLEMENT, eventescrow_deal.settlement_proposedfor each proposal).settlement.buyer_proposalandsettlement.seller_proposalshow the current ones. - Resolver. In a deal that named one, the resolver may rule within
resolve_periodafter the dispute (timeline.resolve_deadline):resolve(buyer_amount, ruling_hash), by the signed criteria only. Its fee comes off the top, and the ruling is what the buyer gets out of the rest (settlement_reason: RESOLVER). - Deadlock. Without a resolver, or once its window has passed, a dispute without matching proposals is a deadlock (
settlement.deadlocked: true). The funds stay locked until both parties propose the same split, the buyer releases or the seller refunds. Neither a timer nor ChainZap can end it.
Money
The service fee is a fixed amount set when the deal is drafted (fee_bps of the amount, by your pilot policy), paid only out of the seller's payout:
- release or the seller's claim: the seller receives the amount minus the fee;
- split: the fee is cut in proportion to the seller's part;
- refund, the buyer's claim or expiry: no fee.
The resolver fee is fixed in the terms and paid only if the resolver decides the dispute. Example: amount 100, resolver fee 5, ruling "buyer 40": the buyer gets 40, the resolver 5 and the seller 55 less the service fee on 55. A settlement by matching proposals, a release or a refund pays the resolver nothing.
balances separates what the contract credited (accrued), what is still to withdraw (claimable) and what has left the contract (withdrawn), each for buyer, seller, fee and resolver. Each party pays the network cost of its own transactions in TRX; ChainZap pays for confirming the funding, closing unfunded deals, crediting excess and pushing payouts.
Create a draft
curl --max-time 15 https://api.chainzap.io/v1/escrow-deals \
-H 'X-API-Key: YOUR_SERVER_API_KEY' -H 'Content-Type: application/json' \
-d '{
"external_reference": "order-2026-10-0042",
"buyer": "TAHXBmAAswvxo1fx7NzQeJe234766SHwG5",
"seller": "TTogA7AhPuChVpzUEePBhPyFi8VsStSAmn",
"amount": "1250.50",
"category": "DIGITAL_GOODS",
"title": "Annual licence key",
"delivery": {
"criteria": ["The key activates on the vendor site", "The licence covers 12 months"],
"method": "Key sent through the order chat",
"evidence_required": ["Screenshot of the activation page"]
},
"timeline": {
"delivery_period_seconds": 259200,
"inspection_period_seconds": 259200
}
}'
This draft has no resolver. To name one, add "resolver_enabled": true, the resolver ("resolver_id", or your policy's default), its fee in token units and its window after a dispute:
{
"resolver_enabled": true,
"resolver_id": "0192f0c4-6f1e-7a3b-9c2d-4e5f60718293",
"resolver_fee": "12.50",
"timeline": {
"delivery_period_seconds": 259200,
"inspection_period_seconds": 259200,
"resolve_period_seconds": 259200
}
}
A deal with a resolver without these settings answers 422 resolver_settings_required; a deal without one that sends any of them answers 422 resolver_settings_without_resolver. The resolver fee may not exceed the share of the amount your policy allows (422 invalid_resolver_fee).
The same external_reference with the same body returns the same draft (replayed: true); with a different body it answers 409 escrow_reference_conflict. Find a draft later with POST /v1/escrow-deals/lookup. Delivery criteria are two to five objective checks: a dispute is argued against these lines only. Categories are limited to digital deliveries with an objective acceptance test, as enabled by your pilot policy.
POST /v1/escrow-deals/{ref}/versions replaces the terms of a draft (send expected_version); signatures on the previous version stop counting. POST /v1/escrow-deals/{ref}/cancel closes a draft. Neither is possible once both parties signed.
Resolvers
A resolver is optional. A deal that names one names an external resolver your platform registered. A resolver is never ChainZap: its address and every key of its TRON account must not be a ChainZap address or key, nor a key of the deal's buyer or seller.
curl --max-time 15 https://api.chainzap.io/v1/escrow-deals/resolvers \
-H 'X-API-Key: YOUR_SERVER_API_KEY' -H 'Content-Type: application/json' \
-d '{
"address": "TJRyWwFs9wTFGZg3JbrVriFbNfCug5tDeC",
"name": "Example dispute service",
"affiliation": "INDEPENDENT",
"rules_version": "dispute-rules/2026-10",
"rules_sha256": "5f0c…64 hex characters"
}'
affiliation is PLATFORM (operated by your platform) or INDEPENDENT; the parties see it, and that your platform registered the resolver. On live the account is read on chain: it must sign rulings with one key (SINGLE_KEY) or two of three keys whose active permission may only call contracts (MULTISIG_2_OF_3); anything else is refused (resolver_scheme_unsupported, resolver_account_not_activated). On the sandbox the read is best effort; a resolver that cannot sign stays registered but eligible: false.
GET /v1/escrow-deals/resolvers lists your resolvers and the shared ones; each shows key_scheme, signatures_required, eligible and ineligible_reason. POST …/resolvers/{id}/verify reads the account again. POST …/resolvers/{id}/disable stops new deals naming it (deals that already name it keep it); …/enable allows them again after a fresh read on live. A registration cannot be edited: a resolver's identity is part of the terms both parties sign, so a different resolver is a new registration. The fee is not part of the registration: each deal sets its own. Up to 20 active resolvers per network (100 registrations in all); another organization's resolver answers 404 resolver_not_found. The developer portal's escrow tab does the same.
Consent
Send the parties the deal link from links. On the deal page each signs in with the wallet named in the deal, sees every term, and signs one text with TronLink (signMessageV2). The page recomputes the terms hash, the deal id and the text from the terms it shows and refuses to offer a signature if anything differs. Every transaction it offers later is checked against the same terms: the escrow address is read from the factory's own registry, a transfer goes only to that escrow and only for the remaining amount, and a withdrawal only to the signed-in party.
To collect signatures in your own interface, read GET /v1/escrow-deals/{ref}/consent: message is the exact text, params the contract parameters and terms the document (chainzap.escrow.terms/2) whose canonical JSON hash is terms_hash. Relay a signature with POST /v1/escrow-deals/{ref}/consents (version, role, signature). A party whose account is controlled by other keys (permission multisig) approves on chain instead (approveTerms in actions).
Both signatures are verified twice: by the API, and by the factory, which renders the same text itself before it creates the contract. The text names the resolver or Resolver: none, and says what silence and a dispute mean. These are its lines for a deal with a resolver, then for one without:
Resolver: TJRyWwFs9wTFGZg3JbrVriFbNfCug5tDeC
Resolver fee: 12.500000 USDT, paid from the escrow only if the resolver decides a dispute
Resolver period after dispute: 3d 00h 00m
If delivery is not marked in time: the buyer can claim a refund
If the buyer neither accepts nor disputes during inspection: the seller can claim payment
In a dispute: no automatic outcome; it settles when buyer and seller propose the same split, or by the resolver within its period; otherwise the funds stay locked
Resolver: none
If delivery is not marked in time: the buyer can claim a refund
If the buyer neither accepts nor disputes during inspection: the seller can claim payment
In a dispute: no automatic outcome; it settles when buyer and seller propose the same split; otherwise the funds stay locked
Party transactions
GET /v1/escrow-deals/{ref}/actions?role=BUYER lists what that party can sign now. Each action carries the contract, the function, the ABI-encoded parameters, a fee limit and an energy estimate:
| Action | Who | Call |
|---|---|---|
TRANSFER_FUNDS |
buyer | transfer(address,uint256) on the token: the escrow and the remaining amount |
CONFIRM_FUNDING |
anyone | confirmFunding() once the escrow holds the amount |
MARK_DELIVERED |
seller | markDelivered(bytes32) with the evidence hash |
RELEASE, REFUND |
buyer, seller | release(), refund() |
CLAIM_REFUND, CLAIM_RELEASE |
buyer, seller | claimRefund() after the delivery deadline, claimRelease() after inspection |
DISPUTE |
buyer | dispute(bytes32) during inspection |
PROPOSE_SETTLEMENT |
buyer, seller | proposeSettlement(uint96); parameters is empty: encode the buyer's amount yourself, from 0 to the deal amount |
EXPIRE, SWEEP_EXCESS |
anyone | expire() after the funding deadline, sweepExcess() when the escrow holds more than it owes |
WITHDRAW |
the recipient | withdraw(address) for a credited payout |
Actions anyone can call are listed under each party's role while they are open. If your own interface builds these transactions, make the same checks before your users sign: the escrow is escrowOf(deal_id) on the factory named in the signed terms, and the token is the factory's. After you relay a transaction, report it with POST /v1/escrow-deals/{ref}/transactions; it counts only when the chain confirms it, and reporting never changes the deal by itself. A report is accepted only while the deal can have that transaction (409 action_not_available) and with at most five pending per party (429 too_many_pending_transactions); a confirmed transaction that is not that call from that party is dropped.
Telegram
links.telegram_invite is a t.me link to the ChainZap bot for this deal; share it with the parties next to the deal link. The bot names no deal details: it opens the deal page in the browser, where every signature and payment happens, and the deal's status in the Telegram Mini App. The status screen shows only deals a party linked from a private chat after signing in with their wallet; nothing can be signed or sent from Telegram. Web and Telegram show the same deal under the same id.
Evidence
POST /v1/escrow-deals/{ref}/evidence adds a text note and PUT /v1/escrow-deals/{ref}/evidence/files?purpose=DELIVERY&file_name=log.pdf a file (PDF, PNG, JPEG, WebP or plain text, up to 10 MiB). Items you add are labelled as submitted by the platform: they show who sent them, not that a delivery happened. Each item keeps its SHA-256, author and time; a replacement is a new item. When a party marks delivery or opens a dispute, the hash of their evidence set is recorded on chain. File contents are deleted after the retention period; the hashes stay.
GET /v1/escrow-deals/{ref}/dispute returns the criteria, both sides' evidence and the dispute deadlines.
Events and webhooks
Every change becomes an event: escrow_deal.created, terms_updated, consent_received, agreed, cancelled, agreement_expired, creation_blocked, contract_created, funded, delivered, disputed, settlement_proposed, settled, excess_credited, payout_withdrawn and evidence_added. Deadline reminders go to the parties by Telegram, not to the webhook.
Set one endpoint per environment with PUT /v1/escrow-deals/webhook ({"url": "https://..."}); the response shows the signing secret once. The endpoint must be HTTPS on port 443 at a public address; redirects are not followed. Each delivery is a POST with:
| Header | Meaning |
|---|---|
X-ChainZap-Event-Id |
the event, the same on every retry |
X-ChainZap-Delivery-Id |
this delivery attempt series |
X-ChainZap-Timestamp |
Unix seconds when signed |
X-ChainZap-Signature |
v1= HMAC-SHA256 of {timestamp}.{delivery_id}.{body} with your secret |
import hashlib, hmac, time
def verify(secret: str, headers: dict, body: bytes) -> bool:
timestamp = int(headers["X-ChainZap-Timestamp"])
if abs(time.time() - timestamp) > 300:
return False
message = f"{timestamp}.{headers['X-ChainZap-Delivery-Id']}.".encode() + body
expected = "v1=" + hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, headers["X-ChainZap-Signature"])
Answer 2xx within 10 seconds. Failed deliveries are retried with growing pauses (30 seconds up to 12 hours, 12 attempts). Delivery is at least once and not in order: deduplicate by X-ChainZap-Event-Id and use sequence to order. GET /v1/escrow-deals/events?after=<sequence> is the full feed to catch up after downtime; POST /v1/escrow-deals/events/{event_id}/redeliver sends one again, POST /v1/escrow-deals/webhook/test sends a signed escrow.ping, POST /v1/escrow-deals/webhook/rotate-secret replaces the secret and DELETE /v1/escrow-deals/webhook stops deliveries.
What changed in protocol v2
New deals use contract and terms version 2. If you integrated with the first pilot version:
- Draft request.
dispute_enabledis nowresolver_enabled: every deal can be disputed, only the resolver is optional. With a resolver sendresolver_id,resolver_feeandtimeline.resolve_period_seconds.timeline.response_period_secondsandtimeout_outcomeare gone: there is no seller answer window and no outcome by timeout in a dispute. - Deal response. New:
protocol_version,resolver.fee,timeline.resolve_deadline,settlement(proposals anddeadlocked, while disputed),funding(while awaiting funds) andresolverin each ofbalances.accrued,claimableandwithdrawn.timeline.if_nobody_actsis now{at, outcome, claim_by}. Gone:dispute_enabled,timeline.response_period_seconds,timeline.seller_response_deadlineandtimeline.seller_responded.settlement_reasonmay beMUTUAL_SETTLEMENT;TIMEOUT_NO_RULINGappears only on archived deals. - Funding and deadlines. Funding is a direct transfer and
confirmFundinginstead of an allowance andfund. After a delivery or inspection deadline the buyer or the seller claims the money; nothing settles by timeout. - Actions. New:
TRANSFER_FUNDS,CONFIRM_FUNDING,CLAIM_REFUND,CLAIM_RELEASE,PROPOSE_SETTLEMENT,EXPIREandSWEEP_EXCESS. Gone:APPROVE_TOKEN,FUND,RESPOND,PROCESS_TIMEOUTandCREDIT_EXCESS. - Events. New:
escrow_deal.settlement_proposedandescrow_deal.excess_credited. Gone:escrow_deal.seller_responded. - Terms.
chainzap.escrow.terms/2addsrules: "chainzap.escrow.rules/2"andresolver.fee, and dropstimeout_outcomeandtimeline.response_period. - Errors. New:
resolver_settings_required,resolver_settings_without_resolver,invalid_resolver_feeandinvalid_buyer_amount. Gone:invalid_simple_deal,dispute_settings_required,dispute_settings_without_disputes,disputes_disabledandinvalid_timeout_outcome.
Deals created before version 2 keep protocol_version: 1. They are archived: the API and the deal page show them read-only from ChainZap's record, and nothing acts on them.
Errors
| Code | When |
|---|---|
403 escrow_not_enabled |
escrow deals are off for this organization or environment |
403 participant_not_allowed |
a live party is not on your pilot list |
422 participant_screening_failed |
a party did not pass address screening; on live, 503 screening_unavailable when a list cannot be checked |
422 deal_amount_above_pilot_cap, 409 pilot_volume_cap_reached |
the deal exceeds your pilot limits |
422 category_not_enabled, 422 resolver_not_available, 422 resolver_not_verified |
the category or resolver is not available |
422 inspection_period_below_policy, 422 resolve_period_below_policy, 422 invalid_period |
a period is shorter than your policy allows or outside the factory's bounds |
422 resolver_settings_required, 422 resolver_settings_without_resolver |
the resolver settings do not match resolver_enabled |
422 invalid_resolver_fee |
the resolver fee exceeds the share your policy allows, or is set without a resolver |
422 resolver_is_chainzap, 422 resolver_is_party, 422 resolver_scheme_unsupported, 422 resolver_account_not_activated |
the resolver cannot be registered or named |
409 resolver_already_registered, 409 resolver_limit_reached, 404 resolver_not_found |
resolver registration |
422 invalid_consent_signature |
the signature does not match the party and these terms |
409 terms_version_conflict, 409 escrow_terms_locked |
the terms changed, or can no longer change |
409 agreement_expired |
the time to sign has run out |
409 action_not_available, 429 too_many_pending_transactions |
a reported transaction is not possible now, or too many are still pending |
404 escrow_not_found |
no such deal in this organization and environment |
All errors use the common format. Escrow requests are limited to 16 KiB of JSON; an evidence file to 10 MiB.
Sandbox
Sandbox keys work on the TRON Nile test network with the test token labelled "ChainZap TEST USD (NO VALUE)". The flow, the pages and the webhooks are the same as live, and the sandbox policy may allow a shorter inspection period to try the flow; no real funds can be involved. Live deals use USDT on TRON mainnet only for pilot organizations, with an allowlist of participants and caps per deal and in total.
GET /v1/usage
Request
curl --include --max-time 15 'https://api.chainzap.io/v1/usage?days=30' \
-H 'X-API-Key: cz_live_000000000000.fictional_example_only' \
-H 'X-Request-ID: merchant-usage-1001'
days is an integer from 1 to 90; the default is 30. This read does not need an idempotency key. Read the X-Request-ID response header. A usage request is rate-limited but does not use checks. Retry only errors marked retryable and respect Retry-After.
Quota for the current period
period.start and period.end delimit the current billing period: the paid period anchored to the confirmed payment, or the UTC calendar month for an organization without a paid plan.
| Field | Meaning |
|---|---|
limit |
Included checks for the period. |
used |
Completed checks that were charged. |
reserved |
Checks that are still running and hold a reservation. |
remaining |
max(0, limit - used - reserved). |
A reservation is released when a request finishes without a charge. balances adds extra checks and the total available; subscription describes the paid period; status: "legacy" with plan: null means your organization's limits were set by agreement (for example a pilot contract) rather than by a self-serve plan, and the limits shown are the ones that apply. See plans and payment. environment is live or sandbox, depending on the key. All API keys of the organization and requests made in the developer dashboard share the same quota.
Statistics for the selected window
recent counts completed logical checks during the requested rolling window of days days. Idempotent HTTP replays are not new check records. It includes charged, error and LIMITED_DATA counts, average latency, networks and the overall-state distribution. It contains no transaction hashes or provider details.
The developer dashboard adds UTC daily buckets, 1/7/30-day counters and p50/p95 latency when at least 20 completed latency samples exist in the last 30 days. Successful-response counts include partial responses; limited coverage is a subset, not an additional total.
The usage chart compares completed requests with charged checks for 7, 30 or 90 days. Hover over the chart, tap it or use the day slider with the arrow keys to inspect exact values. Days without checks show zero; the first and last UTC days may be partial. Live and Sandbox are separate views. The daily table remains available below the charts. The allowance bar shows included checks for the current billing period; extra packages are listed in Plan and billing.
Developer dashboard and plans
After signing in to the developer dashboard, open /dashboard/usage/ for quota counters, daily tables, result distribution and latency statistics. /dashboard/plan/ shows the current plan, monthly quota, requests per minute and the concurrency limit. Networks entitled by the plan and networks currently enabled for checks are displayed separately; an enabled flag is not a live provider health check.
The Playground page accepts automatic network detection or an explicit TRON, Ethereum or TON selection within your available networks. Its checks use the same organization quota and idempotency rules as the server API.
Plans and extra checks packages are bought on the Plan and billing page; see plans and payment. Renewal is manual: there is no automatic charge, invoicing or API wallet. Consumer Mini App subscriptions do not grant B2B API quota. Public documentation does not require sign-in.
Plans, checks and payment (beta)
What you pay for
A check is one API check of a transaction. You pay for a complete, final check only: a response with coverage: complete and a state of CLEAR, REVIEW or HIGH_RISK for a transaction that is confirmed past its finality policy or failed for good. A risky result is a useful result and is charged. A pending transaction, a transaction that was not found, LIMITED_DATA, transport errors, timeouts, quota errors and idempotent replays are not charged on either endpoint; their reservation is released. A successful HTTP response is not the same as a charged check.
Beta plans (pricing policy BETA_PRICING_V0)
A plan gives your organization a number of included checks per billing period.
| Plan | Per month | Included checks | Extra check |
|---|---|---|---|
| Sandbox | free | 50 test checks per UTC month | not sold |
| Starter | $99 | 250 | $0.40 |
| Growth | $299 | 1 000 | $0.30 |
| Business | $999 | 5 000 | $0.20 |
| Scale | individual | individual | individual |
Prices are in US dollars. GET /v1/catalog publishes them in integer minor units (cents). These are preliminary beta terms and may change for future billing periods; an order or a billing period that is already paid keeps the terms it was sold under. Request-rate and concurrency limits are preliminary until general availability. Scale is agreed individually and is not sold online.
curl --max-time 15 https://api.chainzap.io/v1/catalog \
-H 'X-API-Key: cz_live_000000000000.fictional_example_only'
Billing periods and renewal
A paid billing period starts when the payment is confirmed on the server and lasts one calendar month (31 January runs to 28 or 29 February; the anchor day returns afterwards). Renewal is manual: nothing is charged automatically. Paying early schedules the next billing period to start when the current one ends; paying after a gap starts a new billing period immediately. A different plan applies from the next billing period; the current paid period is never reset. Included checks do not carry over.
Extra checks packages
An extra checks package adds checks on top of the included checks. A package contains 100 to 10 000 checks in steps of 50 and costs the extra-check price of your current plan. Extra checks are valid for 12 months from purchase, are used only after the included checks, and can be used only while a paid plan is active. While the plan is inactive they are frozen, not lost. The price is fixed at purchase and is not recalculated by later catalog changes.
Payment
Purchases are made in the developer dashboard by owner, admin and billing members, never with an API key. Payment is in cryptocurrency. Check the total and choose Pay with crypto: the payment page opens, where you pay the exact total in USDT or another coin offered there. The total is fixed in US dollars, and the page stays payable for the order's validity time, at least 15 minutes. If you leave it, the order on the Plan and billing page takes you back to it or cancels the order. Checks are granted only after the server confirms the payment with the payment provider itself: the wallet's own response, a screenshot or returning to the dashboard page does not grant anything. A payment page cannot be withdrawn, so money sent after you cancel an order or after it expires is still credited when it can apply and reviewed by support otherwise. A duplicate or partial payment is recorded and reviewed by support; it is never granted twice.
Balance in the API
curl --max-time 15 'https://api.chainzap.io/v1/usage?days=7' \
-H 'X-API-Key: cz_live_000000000000.fictional_example_only' | jq '.balances, .subscription'
period.remaining keeps its meaning: the included checks left in the current billing period. balances.extra shows extra checks, balances.total_available shows the total that a new check can draw on, and balances.included.reserved shows checks that are still running. subscription reports the billing period, the plan and the manual renewal. The X-Quota-Available header carries the total on check responses. A balance does not override a suspended organization, a network that is not enabled or an inactive plan: 429 quota_exceeded is returned when nothing is available.
Refunds and disputes
Support handles refunds case by case and records them as separate events: the unused remainder of a grant is reversed, checks already used are not clawed back, and the available balance never goes below zero.
Sandbox
Sandbox keys start with cz_test_. They are created in the developer dashboard or by your organization's operator. They call the same endpoints with the same request and response schemas, but never reach data providers, never cost anything and never touch your paid checks. Every sandbox success carries environment: "sandbox", and so does every error the check itself returns (for example provider_unavailable, network_not_enabled, quota and rate limits): branch on that field. A refusal before the check starts (401, 403 tenant_suspended, 503 api_disabled, the per-IP 429 applied before the key is read, 413, 415, a 422 request validation error, invalid_idempotency_key) carries no environment, and an unexpected 500 or 504 may carry none; there the key you sent tells the environment. POST /v1/check and the wallet check also carry details.evidence.source: "sandbox"; POST /v1/transaction/check has no details, and its evidence items name the same source roles as a live answer, so rely on environment. Treat such a result as a fixture, never as an observation. Each fixture explains itself with the same reason_codes the live engine emits, so the branches you write against the sandbox are the branches production takes.
Deterministic outcomes
The first character of the transaction hash selects the outcome, so you can exercise every state on purpose:
| First hex character | Result |
|---|---|
0–3, c, f |
CLEAR, complete coverage |
4–5 |
REVIEW, complete coverage |
6 |
HIGH_RISK from an elevated AML level, complete coverage |
7 |
HIGH_RISK from a sanctions hit (sanctions_hit: true), complete coverage |
8–9 |
LIMITED_DATA, partial coverage, not charged |
a |
transaction not found, as live: transaction_status: NOT_FOUND, retryable, not charged; /v1/check answers 404 transaction_not_found |
b |
provider outage (503 provider_unavailable), not charged |
d |
failed (reverted) transaction: transaction_status: FAILED, recommended_action: NOT_EXECUTED, the *_match fields are null; final, so charged like a live failed transaction |
e |
pending transaction: REVIEW with TX_PENDING_CONFIRMATIONS, complete coverage, not charged |
The sandbox fabricates only what a provider would return. The comparison with your expectations, the status axes, the evidence items and the reasons come from the live engine, so a sandbox answer has the shape and the rules of a live one, contract 0.3 fields included. With the obligation ledger on, sandbox checks, obligations and batches are recorded in a sandbox ledger kept apart from the live one.
curl --max-time 15 https://api.chainzap.io/v1/check \
-H 'X-API-Key: cz_test_000000000000.fictional_example_only' \
-H 'Idempotency-Key: sandbox-demo-1' -H 'Content-Type: application/json' \
--data '{"tx_hash":"8111111111111111111111111111111111111111111111111111111111111111"}'
Without network, the sandbox answers for TRON when TRON is enabled for your organization, otherwise for the first network you have. As in live discovery, the shape of the hash (0x, base64) never selects the network. Send network explicitly to see whether a network is enabled: it answers 403 network_not_enabled in the sandbox exactly as it does live. Base64 TON hashes use the top four bits of the first byte.
Allowance and isolation
The sandbox spends its allowance on exactly what a live check is charged for: a complete, final result. A pending one, a partial one, an absent transaction and the outage fixture cost nothing, as in production; the failed fixture (d) is final and is charged, as a live failed transaction is. If your organization is on the pilot contract, sandbox keys are refused the same way live keys are (expected_fields_required, token_not_enabled, check_kind_not_enabled). expected_recipient, expected_token and expected_amount are compared against the fixture and a mismatch is never CLEAR, so the branch you test is the branch production takes; a nonzero digit beyond the token's decimals answers 422 invalid_expected_amount, as live. Sandbox checks draw on a separate allowance of 50 test checks per UTC calendar month; GET /v1/usage with a sandbox key reports that allowance with environment: "sandbox". Idempotency keys, quota and usage statistics are separate per environment: the same Idempotency-Key in the sandbox and in the live environment are two different operations. A sandbox key cannot buy anything and does not prove that a live network is enabled for your organization.
Wallet fixtures
For POST /v1/wallet/check the sandbox picks the outcome from a hash of the normalised address, so it cannot be steered by the first character. Use one of the pinned addresses below; each row is stable across releases and checked by the test suite.
| Outcome | Result |
|---|---|
clear |
CLEAR, complete coverage, charged |
review |
REVIEW from behaviour, complete coverage, charged |
high_risk_denylist |
HIGH_RISK from a denylist hit, complete coverage, charged |
high_risk_sanctions |
HIGH_RISK from a sanctions match, complete coverage, charged |
limited_data |
LIMITED_DATA, partial coverage, not charged |
review_partial |
REVIEW with indirect exposure and partial counterparty screening, charged |
provider_unavailable |
503 provider_unavailable, not charged |
| Outcome | Ethereum | TRON | TON |
|---|---|---|---|
| clear | 0xc933ee607c865f6fbc6222330dc9166e1cc6d64f |
TPkD2p19tKyRxAyRFyFdAc5vdPifpmtUfc |
0:ad4ab97d14757696f1af317e613adc31b296e683ad1795880c8c906de6daf327 |
| review | 0x0aa8246d9ace486edb4cb7600ac6d40c3c8f884b |
TBBBSYtDqb7szRTcJ9YW4AdrEFTz7a9pvi |
0:fa057a9368fb5432944e6c874d1f92e8a1cd893f88e6f18a868c08a3bf7dc885 |
| high_risk_denylist | 0x1e799ef4c436f1e576f1cf40fb3655ca7e87cd4a |
TZBCVU6RLDLhvJoJUPksGjGMdFh7LngTXy |
0:0ab976607b5b1f1b384b6fe79521bfc2d11a868b2b2ed38e118cc5f1e3e63990 |
| high_risk_sanctions | 0x88c967e52185aef0263776a7efa1521c66a88547 |
TEs2fpP1TLoCwjAwxmwZz7sZVdwrWrKdRQ |
0:bf24aaea2aa3bdd5d48c68ba1cbb7869a50fa2b39b7ed6e2c3c9aec437330461 |
| limited_data | 0x9c689365b5e78b2bab2d1b0f4e0734540fb719f1 |
TFFXvwH4owR9bDNg3g3MG8K1a9mX8PurXm |
0:b5c1220a9967b961b34ff54e836ef02f0942c2b5597c559129b3e5fcfc83dfaa |
| review_partial | 0x5629d9db95999852cb0c0b4e9afd057800800cfb |
TB7fLLjaJqubgudHK5d7mQ754sAds3qsB7 |
0:ecf8f65ba4afdd1da26b0774b59b688907accdaf5e2ae4ef47ad4a3014fc2c2b |
| provider_unavailable | 0xf60ca8315084bc9b55a2f4026d8856f1170ef8db |
TAy5XDN27LLL2eoBbQcota2a3YD9iHc3MT |
0:a765cd5463fe92dbf3e928978ec5c8e04003ae8589d5116fa5a17c1a0507b259 |
Every wallet fixture carries environment: "sandbox" and details.evidence.source: "sandbox", explains itself with the same reason codes as the live engine, and spends the sandbox allowance exactly as a live wallet check spends quota: when a state is produced.
Integration examples
These retry examples and response fixtures use the canonical contract 0.3 POST /v1/transaction/check endpoint with an explicit network. For the shorter /v1/check request and its short response, see one hash check. Both endpoints use the same retry and quota rules.
A successful HTTP response must be evaluated on separate axes: verification_final with integrity_status for payment comparison; risk_status, risk_final and recommended_action for risk and action. Pending never means MATCH; final MATCH with insufficient KYT requires MANUAL_REVIEW. Risk retries use risk_retryable and risk_retry_after_seconds, not verification retryable. See status axes.
Python: idempotent retry
This server-side example uses httpx. The key is fictional. In a real integration, load the API key from your server's secret store and persist operation_key and body in your own operation ledger before the first attempt. After a process restart, reuse both.
import random
import time
import httpx
api_key = "cz_live_000000000000.fictional_example_only"
operation_key = "merchant-order-1001-check-1"
body = {
"network": "tron", "tx_hash": "a" * 64,
"expected_recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"expected_token": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"expected_amount": "1250.000001",
}
def check():
with httpx.Client(timeout=15, follow_redirects=False) as client:
for attempt in range(4):
try:
response = client.post(
"https://api.chainzap.io/v1/transaction/check",
headers={
"X-API-Key": api_key,
"Idempotency-Key": operation_key,
"X-Request-ID": f"order-1001-attempt-{attempt + 1}",
},
json=body,
)
except httpx.TransportError:
if attempt == 3:
raise RuntimeError("unresolved_transport_outcome") from None
time.sleep(2 ** attempt + random.uniform(0, 1))
continue
print("X-Request-ID:", response.headers.get("X-Request-ID"))
try:
result = response.json()
except ValueError:
raise RuntimeError("unresolved_gateway_response") from None
if response.is_success:
return result
error = result.get("error", {})
if error.get("retryable") is not True:
raise RuntimeError(error.get("code", "unresolved_response"))
if response.headers.get("Idempotent-Replayed") == "true":
raise RuntimeError("stored_error_requires_reconciliation")
try:
instructed = int(response.headers.get("Retry-After", "0"))
except ValueError:
raise RuntimeError("invalid_retry_after") from None
delay = max(instructed, 2 ** attempt) + random.uniform(0, 1)
if attempt == 3 or delay > 30:
raise RuntimeError("schedule_retry_with_same_operation_key")
time.sleep(delay)
The loop handles retryable 409/429/503/504 responses and network uncertainty without creating another logical operation. Handle the returned business states according to your payment workflow. Do not log body or the entire result.
JavaScript / TypeScript: server request
Use this code on your server, never in a browser with a live key. The operation key and body must be persisted before calling the function, just as in the Python example.
type PublicResult = {
request_id?: string;
error?: { code: string; message: string; retryable: boolean };
[field: string]: unknown;
};
const apiKey = "cz_live_000000000000.fictional_example_only";
const operationKey = "merchant-order-1001-check-1";
const body = {
network: "tron", tx_hash: "a".repeat(64),
expected_recipient: "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
expected_token: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
expected_amount: "1250.000001",
};
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
async function check(): Promise<PublicResult> {
for (let attempt = 0; attempt < 4; attempt++) {
let response: Response;
try {
response = await fetch("https://api.chainzap.io/v1/transaction/check", {
method: "POST", redirect: "error", signal: AbortSignal.timeout(15000),
headers: {
"Content-Type": "application/json", "X-API-Key": apiKey,
"Idempotency-Key": operationKey,
"X-Request-ID": `order-1001-attempt-${attempt + 1}`,
},
body: JSON.stringify(body),
});
} catch {
if (attempt === 3) throw new Error("unresolved_transport_outcome");
await wait((2 ** attempt + Math.random()) * 1000);
continue;
}
console.info("X-Request-ID:", response.headers.get("X-Request-ID"));
const result = await response.json() as PublicResult;
if (response.ok) return result;
if (result.error?.retryable !== true) {
throw new Error(result.error?.code ?? "unresolved_response");
}
if (response.headers.get("Idempotent-Replayed") === "true") {
throw new Error("stored_error_requires_reconciliation");
}
const instructed = Number(response.headers.get("Retry-After") ?? "0");
if (!Number.isFinite(instructed) || instructed < 0) {
throw new Error("invalid_retry_after");
}
const delay = Math.max(instructed, 2 ** attempt) + Math.random();
if (attempt === 3 || delay > 30) {
throw new Error("schedule_retry_with_same_operation_key");
}
await wait(delay * 1000);
}
throw new Error("retry_budget_exhausted");
}
Response scenarios
The following synthetic fixtures illustrate valid response shapes, not live checks. Every sample has an X-Request-ID header equal to its request_id. Inspect null values and coverage as well as the overall state.
Confirmed transaction
View full JSON response
{
"request_id": "example-confirmed",
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"network": "tron",
"transaction_type": "TriggerSmartContract",
"transaction_category": "trc20_transfer",
"transaction_state": "confirmed",
"confirmations": 27,
"required_confirmations": 19,
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"transfers": [
{
"index": 0,
"asset_type": "trc20",
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_id": null,
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"event_ref": "log:0",
"execution_status": "success"
}
],
"transfers_truncated": false,
"aml_risk_level": "low",
"schema_version": "0.3",
"policy_version": "b2b-tx-2026-10.4",
"sanctions_hit": false,
"direct_sanctions_match": false,
"indirect_sanctions_exposure": false,
"risk_exposure": false,
"key_exposure": [],
"token_authenticity": "official",
"recipient_match": true,
"token_match": true,
"amount_match": true,
"coverage": "complete",
"workflow_coverage": "complete",
"source_coverage": {
"sanctions_sources": {
"ofac": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": 172800,
"scope": "configured_address_index",
"error_code": null
},
"eu": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:49:24Z",
"data_updated_at": "2026-09-22T18:01:34Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"uk": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:47:32Z",
"data_updated_at": "2026-10-02T00:00:00Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"un": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "configured_address_index",
"error_code": null
}
},
"transaction_sources": {
"chain_explorer": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
},
"chain_node": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
}
},
"risk_sources": {
"aml_provider": {
"status": "checked_freshness_unknown",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_risk_score",
"error_code": null
}
},
"universal_clearance": false
},
"freshness": {
"checked_at": "2026-10-10T09:00:00Z",
"transaction_at": "2026-10-10T09:00:00Z",
"risk_data_at": "2026-10-10T09:00:00Z",
"token_data_at": "2026-10-10T09:00:00Z",
"max_source_age_seconds": 0
},
"overall_state": "CLEAR",
"environment": "live",
"reasons": [
{
"code": "TX_FACTS_VERIFIED",
"category": "transaction",
"severity": "info"
},
{
"code": "TX_FINALIZED",
"category": "transaction",
"severity": "info"
},
{
"code": "AML_LOW",
"category": "risk",
"severity": "info"
},
{
"code": "NO_DIRECT_SANCTIONS_MATCH",
"category": "sanctions",
"severity": "info"
},
{
"code": "TOKEN_OFFICIAL",
"category": "token",
"severity": "info"
}
],
"decision_id": null,
"direction": null,
"workflow_type": null,
"versions": {
"decision": "b2b-tx-2026-10.4",
"rules": {
"exposure": "b2b-exp-v2",
"sanctions_freshness": "sf-v1",
"billing": "final_answers_only",
"integrity": "int-v3",
"reuse": "reuse-v1",
"allocation": "alloc-v1"
},
"reason_codes": "rc-1",
"evidence_schema": "ev-1",
"contract": "0.3"
},
"transaction_status": "CONFIRMED",
"integrity_status": "MATCH",
"risk_status": "NO_MATERIAL_SIGNAL",
"coverage_status": "OK",
"status_drivers": {
"transaction": "TX_FINALIZED",
"integrity": null,
"risk": null,
"coverage": null,
"action": "CUSTOMER_STATE_UNKNOWN"
},
"result_final": true,
"verification_final": true,
"risk_final": true,
"risk_retryable": false,
"risk_retry_after_seconds": null,
"retryable": false,
"retry_after_seconds": null,
"recommended_action": "CONFIRM_INTERNAL_STATE",
"integrity": {
"status": "MATCH",
"selected_event_ref": "log:0",
"relevant_event_count": 1,
"comparisons": {
"recipient": {
"expected": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"actual": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"result": "MATCH"
},
"sender": {
"expected": null,
"actual": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"result": "NOT_EVALUATED"
},
"token": {
"expected": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"actual": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"result": "MATCH"
},
"amount": {
"expected": "1250.000001",
"actual": "1250.000001",
"result": "EXACT",
"tolerance": null,
"delta": "0",
"delta_raw": "0"
},
"network": {
"expected": null,
"actual": "tron",
"result": "NOT_EVALUATED"
}
}
},
"risk": {
"status": "NO_MATERIAL_SIGNAL",
"driver": null,
"driver_evidence_ids": []
},
"evidence_items": [
{
"evidence_id": "ev_431b2fd74ad43ef5",
"kind": "transaction_facts",
"source": "chain_explorer",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_63c8c4e421f6ff66",
"kind": "transaction_facts",
"source": "chain_node",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_896f4ce46de5246c",
"kind": "aml_risk",
"source": "aml_provider",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "transaction_risk_score",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked_freshness_unknown",
"freshness": {
"age_seconds": 0,
"stale": true,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_7d0537ae6c2054d5",
"kind": "sanctions_list",
"source": "ofac",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 172800
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_2be872923c0687c9",
"kind": "sanctions_list",
"source": "eu",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-09-22T18:01:34Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_df2204c780968cb5",
"kind": "sanctions_list",
"source": "uk",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-02T00:00:00Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_76c33d7fb3a48fb7",
"kind": "sanctions_list",
"source": "un",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_81b44db3a9445d39",
"kind": "token_authenticity",
"source": "token_registry",
"subject": {
"type": "token",
"ref": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
},
"source_reference": "official",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
}
],
"coverage_limitations": {
"runtime": [],
"product": [
"AML_TRANSACTION_LEVEL_ONLY",
"RISK_STATE_AS_OF_CHECK",
"SANCTIONS_CONFIGURED_LISTS_ONLY"
]
},
"obligation": null,
"reuse": null
}
Awaiting confirmation
View full JSON response
{
"request_id": "example-pending",
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"network": "tron",
"transaction_type": "TriggerSmartContract",
"transaction_category": "trc20_transfer",
"transaction_state": "pending",
"confirmations": 3,
"required_confirmations": 19,
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"transfers": [
{
"index": 0,
"asset_type": "trc20",
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_id": null,
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"event_ref": "log:0",
"execution_status": "success"
}
],
"transfers_truncated": false,
"aml_risk_level": "low",
"schema_version": "0.3",
"policy_version": "b2b-tx-2026-10.4",
"sanctions_hit": false,
"direct_sanctions_match": false,
"indirect_sanctions_exposure": false,
"risk_exposure": false,
"key_exposure": [],
"token_authenticity": "official",
"recipient_match": null,
"token_match": null,
"amount_match": null,
"coverage": "complete",
"workflow_coverage": "complete",
"source_coverage": {
"sanctions_sources": {
"ofac": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": 172800,
"scope": "configured_address_index",
"error_code": null
},
"eu": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:49:24Z",
"data_updated_at": "2026-09-22T18:01:34Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"uk": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:47:32Z",
"data_updated_at": "2026-10-02T00:00:00Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"un": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "configured_address_index",
"error_code": null
}
},
"transaction_sources": {
"chain_explorer": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
},
"chain_node": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
}
},
"risk_sources": {
"aml_provider": {
"status": "checked_freshness_unknown",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_risk_score",
"error_code": null
}
},
"universal_clearance": false
},
"freshness": {
"checked_at": "2026-10-10T09:00:00Z",
"transaction_at": "2026-10-10T09:00:00Z",
"risk_data_at": "2026-10-10T09:00:00Z",
"token_data_at": "2026-10-10T09:00:00Z",
"max_source_age_seconds": 0
},
"overall_state": "REVIEW",
"environment": "live",
"reasons": [
{
"code": "TX_PENDING_CONFIRMATIONS",
"category": "transaction",
"severity": "warning"
},
{
"code": "TX_FACTS_VERIFIED",
"category": "transaction",
"severity": "info"
},
{
"code": "AML_LOW",
"category": "risk",
"severity": "info"
},
{
"code": "NO_DIRECT_SANCTIONS_MATCH",
"category": "sanctions",
"severity": "info"
},
{
"code": "TOKEN_OFFICIAL",
"category": "token",
"severity": "info"
}
],
"decision_id": null,
"direction": null,
"workflow_type": null,
"versions": {
"decision": "b2b-tx-2026-10.4",
"rules": {
"exposure": "b2b-exp-v2",
"sanctions_freshness": "sf-v1",
"billing": "final_answers_only",
"integrity": "int-v3",
"reuse": "reuse-v1",
"allocation": "alloc-v1"
},
"reason_codes": "rc-1",
"evidence_schema": "ev-1",
"contract": "0.3"
},
"transaction_status": "PENDING",
"integrity_status": "NOT_EVALUATED",
"risk_status": "NO_MATERIAL_SIGNAL",
"coverage_status": "OK",
"status_drivers": {
"transaction": "TX_PENDING_CONFIRMATIONS",
"integrity": "TX_PENDING_CONFIRMATIONS",
"risk": null,
"coverage": null,
"action": "TX_PENDING_CONFIRMATIONS"
},
"result_final": false,
"verification_final": false,
"risk_final": false,
"risk_retryable": true,
"risk_retry_after_seconds": 48,
"retryable": true,
"retry_after_seconds": 48,
"recommended_action": "RECHECK_LATER",
"integrity": {
"status": "NOT_EVALUATED",
"selected_event_ref": "log:0",
"relevant_event_count": 1,
"comparisons": {
"recipient": {
"expected": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"actual": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"result": "NOT_EVALUATED"
},
"sender": {
"expected": null,
"actual": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"result": "NOT_EVALUATED"
},
"token": {
"expected": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"actual": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"result": "NOT_EVALUATED"
},
"amount": {
"expected": "1250.000001",
"actual": "1250.000001",
"result": "NOT_EVALUATED",
"tolerance": null,
"delta": null,
"delta_raw": null
},
"network": {
"expected": null,
"actual": "tron",
"result": "NOT_EVALUATED"
}
}
},
"risk": {
"status": "NO_MATERIAL_SIGNAL",
"driver": null,
"driver_evidence_ids": []
},
"evidence_items": [
{
"evidence_id": "ev_431b2fd74ad43ef5",
"kind": "transaction_facts",
"source": "chain_explorer",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_63c8c4e421f6ff66",
"kind": "transaction_facts",
"source": "chain_node",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_896f4ce46de5246c",
"kind": "aml_risk",
"source": "aml_provider",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "transaction_risk_score",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked_freshness_unknown",
"freshness": {
"age_seconds": 0,
"stale": true,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_7d0537ae6c2054d5",
"kind": "sanctions_list",
"source": "ofac",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 172800
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_2be872923c0687c9",
"kind": "sanctions_list",
"source": "eu",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-09-22T18:01:34Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_df2204c780968cb5",
"kind": "sanctions_list",
"source": "uk",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-02T00:00:00Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_76c33d7fb3a48fb7",
"kind": "sanctions_list",
"source": "un",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_81b44db3a9445d39",
"kind": "token_authenticity",
"source": "token_registry",
"subject": {
"type": "token",
"ref": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
},
"source_reference": "official",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
}
],
"coverage_limitations": {
"runtime": [],
"product": [
"AML_TRANSACTION_LEVEL_ONLY",
"RISK_STATE_AS_OF_CHECK",
"SANCTIONS_CONFIGURED_LISTS_ONLY"
]
},
"obligation": null,
"reuse": null
}
Failed transaction
View full JSON response
{
"request_id": "example-failed",
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"network": "tron",
"transaction_type": "TriggerSmartContract",
"transaction_category": "trc20_transfer",
"transaction_state": "failed",
"confirmations": 27,
"required_confirmations": 19,
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": null,
"token_symbol": null,
"decimals": null,
"amount": null,
"transfers": [],
"transfers_truncated": false,
"aml_risk_level": "unknown",
"schema_version": "0.3",
"policy_version": "b2b-tx-2026-10.4",
"sanctions_hit": null,
"direct_sanctions_match": null,
"indirect_sanctions_exposure": null,
"risk_exposure": null,
"key_exposure": [],
"token_authenticity": "official",
"recipient_match": null,
"token_match": null,
"amount_match": null,
"coverage": "complete",
"workflow_coverage": "complete",
"source_coverage": {
"sanctions_sources": {
"ofac": {
"status": "not_checked",
"checked_at": null,
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": 172800,
"scope": "configured_address_index",
"error_code": null
},
"eu": {
"status": "not_checked",
"checked_at": null,
"retrieved_at": "2026-10-02T23:49:24Z",
"data_updated_at": "2026-09-22T18:01:34Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"uk": {
"status": "not_checked",
"checked_at": null,
"retrieved_at": "2026-10-02T23:47:32Z",
"data_updated_at": "2026-10-02T00:00:00Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"un": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "configured_address_index",
"error_code": null
}
},
"transaction_sources": {
"chain_explorer": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
},
"chain_node": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
}
},
"risk_sources": {
"aml_provider": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_risk_score",
"error_code": null
}
},
"universal_clearance": false
},
"freshness": {
"checked_at": "2026-10-10T09:00:00Z",
"transaction_at": "2026-10-10T09:00:00Z",
"risk_data_at": null,
"token_data_at": "2026-10-10T09:00:00Z",
"max_source_age_seconds": 0
},
"overall_state": "REVIEW",
"environment": "live",
"reasons": [
{
"code": "TX_REVERTED",
"category": "transaction",
"severity": "warning"
},
{
"code": "TX_FACTS_VERIFIED",
"category": "transaction",
"severity": "info"
}
],
"decision_id": null,
"direction": null,
"workflow_type": null,
"versions": {
"decision": "b2b-tx-2026-10.4",
"rules": {
"exposure": "b2b-exp-v2",
"sanctions_freshness": "sf-v1",
"billing": "final_answers_only",
"integrity": "int-v3",
"reuse": "reuse-v1",
"allocation": "alloc-v1"
},
"reason_codes": "rc-1",
"evidence_schema": "ev-1",
"contract": "0.3"
},
"transaction_status": "FAILED",
"integrity_status": "NOT_EVALUATED",
"risk_status": "NOT_EVALUATED",
"coverage_status": "SKIPPED",
"status_drivers": {
"transaction": "TX_REVERTED",
"integrity": "TX_REVERTED",
"risk": "TX_REVERTED",
"coverage": null,
"action": "TX_REVERTED"
},
"result_final": true,
"verification_final": true,
"risk_final": true,
"risk_retryable": false,
"risk_retry_after_seconds": null,
"retryable": false,
"retry_after_seconds": null,
"recommended_action": "NOT_EXECUTED",
"integrity": {
"status": "NOT_EVALUATED",
"selected_event_ref": null,
"relevant_event_count": 0,
"comparisons": {
"recipient": null,
"sender": null,
"token": null,
"amount": null,
"network": {
"expected": null,
"actual": "tron",
"result": "NOT_EVALUATED"
}
}
},
"risk": {
"status": "NOT_EVALUATED",
"driver": "TX_REVERTED",
"driver_evidence_ids": []
},
"evidence_items": [
{
"evidence_id": "ev_431b2fd74ad43ef5",
"kind": "transaction_facts",
"source": "chain_explorer",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_63c8c4e421f6ff66",
"kind": "transaction_facts",
"source": "chain_node",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_73e84774c4ced93d",
"kind": "aml_risk",
"source": "aml_provider",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "transaction_risk_score",
"observed_at": null,
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_6b44582b97147dc6",
"kind": "sanctions_list",
"source": "ofac",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_checked",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": 172800
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_06483bdcf9ba67c5",
"kind": "sanctions_list",
"source": "eu",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": "2026-09-22T18:01:34Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_checked",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_9ea21340c566a061",
"kind": "sanctions_list",
"source": "uk",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": "2026-10-02T00:00:00Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_checked",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_76c33d7fb3a48fb7",
"kind": "sanctions_list",
"source": "un",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
}
],
"coverage_limitations": {
"runtime": [],
"product": [
"AML_TRANSACTION_LEVEL_ONLY",
"RISK_STATE_AS_OF_CHECK",
"SANCTIONS_CONFIGURED_LISTS_ONLY"
]
},
"obligation": null,
"reuse": null
}
Transaction not found
View full JSON response
{
"request_id": "example-not-found",
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"network": "tron",
"transaction_type": "TriggerSmartContract",
"transaction_category": "trc20_transfer",
"transaction_state": "not_found",
"confirmations": null,
"required_confirmations": 19,
"sender": null,
"recipient": null,
"token_contract": null,
"token_symbol": null,
"decimals": null,
"amount": null,
"transfers": [],
"transfers_truncated": false,
"aml_risk_level": "unknown",
"schema_version": "0.3",
"policy_version": "b2b-tx-2026-10.4",
"sanctions_hit": null,
"direct_sanctions_match": null,
"indirect_sanctions_exposure": null,
"risk_exposure": null,
"key_exposure": [],
"token_authenticity": "official",
"recipient_match": null,
"token_match": null,
"amount_match": null,
"coverage": "partial",
"workflow_coverage": "partial",
"source_coverage": {
"sanctions_sources": {
"ofac": {
"status": "not_checked",
"checked_at": null,
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": 172800,
"scope": "configured_address_index",
"error_code": null
},
"eu": {
"status": "not_checked",
"checked_at": null,
"retrieved_at": "2026-10-02T23:49:24Z",
"data_updated_at": "2026-09-22T18:01:34Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"uk": {
"status": "not_checked",
"checked_at": null,
"retrieved_at": "2026-10-02T23:47:32Z",
"data_updated_at": "2026-10-02T00:00:00Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"un": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "configured_address_index",
"error_code": null
}
},
"transaction_sources": {
"chain_explorer": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
},
"chain_node": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
}
},
"risk_sources": {
"aml_provider": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_risk_score",
"error_code": null
}
},
"universal_clearance": false
},
"freshness": {
"checked_at": "2026-10-10T09:00:00Z",
"transaction_at": null,
"risk_data_at": null,
"token_data_at": "2026-10-10T09:00:00Z",
"max_source_age_seconds": 0
},
"overall_state": "LIMITED_DATA",
"environment": "live",
"reasons": [
{
"code": "TX_NOT_FOUND",
"category": "transaction",
"severity": "warning"
},
{
"code": "EXPECTED_DATA_UNAVAILABLE",
"category": "expected",
"severity": "warning"
},
{
"code": "TX_FACTS_VERIFIED",
"category": "transaction",
"severity": "info"
}
],
"decision_id": null,
"direction": null,
"workflow_type": null,
"versions": {
"decision": "b2b-tx-2026-10.4",
"rules": {
"exposure": "b2b-exp-v2",
"sanctions_freshness": "sf-v1",
"billing": "final_answers_only",
"integrity": "int-v3",
"reuse": "reuse-v1",
"allocation": "alloc-v1"
},
"reason_codes": "rc-1",
"evidence_schema": "ev-1",
"contract": "0.3"
},
"transaction_status": "NOT_FOUND",
"integrity_status": "NOT_EVALUATED",
"risk_status": "NOT_EVALUATED",
"coverage_status": "SKIPPED",
"status_drivers": {
"transaction": "TX_NOT_FOUND",
"integrity": "TX_NOT_FOUND",
"risk": "TX_NOT_FOUND",
"coverage": null,
"action": "TX_NOT_FOUND"
},
"result_final": false,
"verification_final": false,
"risk_final": false,
"risk_retryable": true,
"risk_retry_after_seconds": 15,
"retryable": true,
"retry_after_seconds": 15,
"recommended_action": "RECHECK_LATER",
"integrity": {
"status": "NOT_EVALUATED",
"selected_event_ref": null,
"relevant_event_count": 0,
"comparisons": {
"recipient": null,
"sender": null,
"token": null,
"amount": null,
"network": {
"expected": null,
"actual": "tron",
"result": "NOT_EVALUATED"
}
}
},
"risk": {
"status": "NOT_EVALUATED",
"driver": "TX_NOT_FOUND",
"driver_evidence_ids": []
},
"evidence_items": [
{
"evidence_id": "ev_431b2fd74ad43ef5",
"kind": "transaction_facts",
"source": "chain_explorer",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": null,
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_63c8c4e421f6ff66",
"kind": "transaction_facts",
"source": "chain_node",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": null,
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_73e84774c4ced93d",
"kind": "aml_risk",
"source": "aml_provider",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "transaction_risk_score",
"observed_at": null,
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_6b44582b97147dc6",
"kind": "sanctions_list",
"source": "ofac",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_checked",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": 172800
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_06483bdcf9ba67c5",
"kind": "sanctions_list",
"source": "eu",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": "2026-09-22T18:01:34Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_checked",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_9ea21340c566a061",
"kind": "sanctions_list",
"source": "uk",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": "2026-10-02T00:00:00Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_checked",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_76c33d7fb3a48fb7",
"kind": "sanctions_list",
"source": "un",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
}
],
"coverage_limitations": {
"runtime": [],
"product": [
"AML_TRANSACTION_LEVEL_ONLY",
"RISK_STATE_AS_OF_CHECK",
"SANCTIONS_CONFIGURED_LISTS_ONLY"
]
},
"obligation": null,
"reuse": null
}
Limited data
View full JSON response
{
"request_id": "example-limited-data",
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"network": "tron",
"transaction_type": "TriggerSmartContract",
"transaction_category": "trc20_transfer",
"transaction_state": "confirmed",
"confirmations": 27,
"required_confirmations": 19,
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"transfers": [
{
"index": 0,
"asset_type": "trc20",
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_id": null,
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"event_ref": "log:0",
"execution_status": "success"
}
],
"transfers_truncated": false,
"aml_risk_level": "unknown",
"schema_version": "0.3",
"policy_version": "b2b-tx-2026-10.4",
"sanctions_hit": false,
"direct_sanctions_match": false,
"indirect_sanctions_exposure": false,
"risk_exposure": false,
"key_exposure": [],
"token_authenticity": "official",
"recipient_match": true,
"token_match": true,
"amount_match": true,
"coverage": "partial",
"workflow_coverage": "partial",
"source_coverage": {
"sanctions_sources": {
"ofac": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": 172800,
"scope": "configured_address_index",
"error_code": null
},
"eu": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:49:24Z",
"data_updated_at": "2026-09-22T18:01:34Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"uk": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:47:32Z",
"data_updated_at": "2026-10-02T00:00:00Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"un": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "configured_address_index",
"error_code": null
}
},
"transaction_sources": {
"chain_explorer": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
},
"chain_node": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
}
},
"risk_sources": {
"aml_provider": {
"status": "unavailable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_risk_score",
"error_code": "timeout"
}
},
"universal_clearance": false
},
"freshness": {
"checked_at": "2026-10-10T09:00:00Z",
"transaction_at": "2026-10-10T09:00:00Z",
"risk_data_at": null,
"token_data_at": "2026-10-10T09:00:00Z",
"max_source_age_seconds": 0
},
"overall_state": "LIMITED_DATA",
"environment": "live",
"reasons": [
{
"code": "AML_UNAVAILABLE",
"category": "risk",
"severity": "warning"
},
{
"code": "TX_FACTS_VERIFIED",
"category": "transaction",
"severity": "info"
},
{
"code": "TX_FINALIZED",
"category": "transaction",
"severity": "info"
},
{
"code": "NO_DIRECT_SANCTIONS_MATCH",
"category": "sanctions",
"severity": "info"
},
{
"code": "TOKEN_OFFICIAL",
"category": "token",
"severity": "info"
}
],
"decision_id": null,
"direction": null,
"workflow_type": null,
"versions": {
"decision": "b2b-tx-2026-10.4",
"rules": {
"exposure": "b2b-exp-v2",
"sanctions_freshness": "sf-v1",
"billing": "final_answers_only",
"integrity": "int-v3",
"reuse": "reuse-v1",
"allocation": "alloc-v1"
},
"reason_codes": "rc-1",
"evidence_schema": "ev-1",
"contract": "0.3"
},
"transaction_status": "CONFIRMED",
"integrity_status": "MATCH",
"risk_status": "INSUFFICIENT",
"coverage_status": "UNAVAILABLE",
"status_drivers": {
"transaction": "TX_FINALIZED",
"integrity": null,
"risk": "AML_UNAVAILABLE",
"coverage": "AML_UNAVAILABLE",
"action": "AML_UNAVAILABLE"
},
"result_final": true,
"verification_final": true,
"risk_final": false,
"risk_retryable": true,
"risk_retry_after_seconds": 30,
"retryable": false,
"retry_after_seconds": null,
"recommended_action": "MANUAL_REVIEW",
"integrity": {
"status": "MATCH",
"selected_event_ref": "log:0",
"relevant_event_count": 1,
"comparisons": {
"recipient": {
"expected": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"actual": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"result": "MATCH"
},
"sender": {
"expected": null,
"actual": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"result": "NOT_EVALUATED"
},
"token": {
"expected": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"actual": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"result": "MATCH"
},
"amount": {
"expected": "1250.000001",
"actual": "1250.000001",
"result": "EXACT",
"tolerance": null,
"delta": "0",
"delta_raw": "0"
},
"network": {
"expected": null,
"actual": "tron",
"result": "NOT_EVALUATED"
}
}
},
"risk": {
"status": "INSUFFICIENT",
"driver": "AML_UNAVAILABLE",
"driver_evidence_ids": []
},
"evidence_items": [
{
"evidence_id": "ev_431b2fd74ad43ef5",
"kind": "transaction_facts",
"source": "chain_explorer",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_63c8c4e421f6ff66",
"kind": "transaction_facts",
"source": "chain_node",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_73e84774c4ced93d",
"kind": "aml_risk",
"source": "aml_provider",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "transaction_risk_score",
"observed_at": null,
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "unavailable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_7d0537ae6c2054d5",
"kind": "sanctions_list",
"source": "ofac",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 172800
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_2be872923c0687c9",
"kind": "sanctions_list",
"source": "eu",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-09-22T18:01:34Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_df2204c780968cb5",
"kind": "sanctions_list",
"source": "uk",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-02T00:00:00Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_76c33d7fb3a48fb7",
"kind": "sanctions_list",
"source": "un",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_81b44db3a9445d39",
"kind": "token_authenticity",
"source": "token_registry",
"subject": {
"type": "token",
"ref": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
},
"source_reference": "official",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
}
],
"coverage_limitations": {
"runtime": [
"AML_UNAVAILABLE"
],
"product": [
"AML_TRANSACTION_LEVEL_ONLY",
"RISK_STATE_AS_OF_CHECK",
"SANCTIONS_CONFIGURED_LISTS_ONLY"
]
},
"obligation": null,
"reuse": null
}
Sanctions match
View full JSON response
{
"request_id": "example-sanctions-hit",
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"network": "tron",
"transaction_type": "TriggerSmartContract",
"transaction_category": "trc20_transfer",
"transaction_state": "confirmed",
"confirmations": 27,
"required_confirmations": 19,
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"transfers": [
{
"index": 0,
"asset_type": "trc20",
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_id": null,
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"event_ref": "log:0",
"execution_status": "success"
}
],
"transfers_truncated": false,
"aml_risk_level": "low",
"schema_version": "0.3",
"policy_version": "b2b-tx-2026-10.4",
"sanctions_hit": true,
"direct_sanctions_match": true,
"indirect_sanctions_exposure": false,
"risk_exposure": false,
"key_exposure": [],
"token_authenticity": "official",
"recipient_match": true,
"token_match": true,
"amount_match": true,
"coverage": "complete",
"workflow_coverage": "complete",
"source_coverage": {
"sanctions_sources": {
"ofac": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": 172800,
"scope": "configured_address_index",
"error_code": null
},
"eu": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:49:24Z",
"data_updated_at": "2026-09-22T18:01:34Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"uk": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:47:32Z",
"data_updated_at": "2026-10-02T00:00:00Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"un": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "configured_address_index",
"error_code": null
}
},
"transaction_sources": {
"chain_explorer": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
},
"chain_node": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
}
},
"risk_sources": {
"aml_provider": {
"status": "checked_freshness_unknown",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_risk_score",
"error_code": null
}
},
"universal_clearance": false
},
"freshness": {
"checked_at": "2026-10-10T09:00:00Z",
"transaction_at": "2026-10-10T09:00:00Z",
"risk_data_at": "2026-10-10T09:00:00Z",
"token_data_at": "2026-10-10T09:00:00Z",
"max_source_age_seconds": 0
},
"overall_state": "HIGH_RISK",
"environment": "live",
"reasons": [
{
"code": "DIRECT_SANCTIONS_MATCH",
"category": "sanctions",
"severity": "critical"
},
{
"code": "TX_FACTS_VERIFIED",
"category": "transaction",
"severity": "info"
},
{
"code": "TX_FINALIZED",
"category": "transaction",
"severity": "info"
},
{
"code": "AML_LOW",
"category": "risk",
"severity": "info"
},
{
"code": "TOKEN_OFFICIAL",
"category": "token",
"severity": "info"
}
],
"decision_id": null,
"direction": null,
"workflow_type": null,
"versions": {
"decision": "b2b-tx-2026-10.4",
"rules": {
"exposure": "b2b-exp-v2",
"sanctions_freshness": "sf-v1",
"billing": "final_answers_only",
"integrity": "int-v3",
"reuse": "reuse-v1",
"allocation": "alloc-v1"
},
"reason_codes": "rc-1",
"evidence_schema": "ev-1",
"contract": "0.3"
},
"transaction_status": "CONFIRMED",
"integrity_status": "MATCH",
"risk_status": "HIGH_RISK",
"coverage_status": "OK",
"status_drivers": {
"transaction": "TX_FINALIZED",
"integrity": null,
"risk": "DIRECT_SANCTIONS_MATCH",
"coverage": null,
"action": "DIRECT_SANCTIONS_MATCH"
},
"result_final": true,
"verification_final": true,
"risk_final": true,
"risk_retryable": false,
"risk_retry_after_seconds": null,
"retryable": false,
"retry_after_seconds": null,
"recommended_action": "HOLD_AND_ESCALATE",
"integrity": {
"status": "MATCH",
"selected_event_ref": "log:0",
"relevant_event_count": 1,
"comparisons": {
"recipient": {
"expected": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"actual": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"result": "MATCH"
},
"sender": {
"expected": null,
"actual": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"result": "NOT_EVALUATED"
},
"token": {
"expected": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"actual": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"result": "MATCH"
},
"amount": {
"expected": "1250.000001",
"actual": "1250.000001",
"result": "EXACT",
"tolerance": null,
"delta": "0",
"delta_raw": "0"
},
"network": {
"expected": null,
"actual": "tron",
"result": "NOT_EVALUATED"
}
}
},
"risk": {
"status": "HIGH_RISK",
"driver": "DIRECT_SANCTIONS_MATCH",
"driver_evidence_ids": []
},
"evidence_items": [
{
"evidence_id": "ev_431b2fd74ad43ef5",
"kind": "transaction_facts",
"source": "chain_explorer",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_63c8c4e421f6ff66",
"kind": "transaction_facts",
"source": "chain_node",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_896f4ce46de5246c",
"kind": "aml_risk",
"source": "aml_provider",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "transaction_risk_score",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked_freshness_unknown",
"freshness": {
"age_seconds": 0,
"stale": true,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_7d0537ae6c2054d5",
"kind": "sanctions_list",
"source": "ofac",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 172800
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_2be872923c0687c9",
"kind": "sanctions_list",
"source": "eu",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-09-22T18:01:34Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_df2204c780968cb5",
"kind": "sanctions_list",
"source": "uk",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-02T00:00:00Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_76c33d7fb3a48fb7",
"kind": "sanctions_list",
"source": "un",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_81b44db3a9445d39",
"kind": "token_authenticity",
"source": "token_registry",
"subject": {
"type": "token",
"ref": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
},
"source_reference": "official",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
}
],
"coverage_limitations": {
"runtime": [],
"product": [
"AML_TRANSACTION_LEVEL_ONLY",
"RISK_STATE_AS_OF_CHECK",
"SANCTIONS_CONFIGURED_LISTS_ONLY"
]
},
"obligation": null,
"reuse": null
}
Payment details do not match
View full JSON response
{
"request_id": "example-expected-mismatch",
"tx_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"network": "tron",
"transaction_type": "TriggerSmartContract",
"transaction_category": "trc20_transfer",
"transaction_state": "confirmed",
"confirmations": 27,
"required_confirmations": 19,
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"transfers": [
{
"index": 0,
"asset_type": "trc20",
"sender": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"recipient": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"token_id": null,
"token_symbol": "USDT",
"decimals": 6,
"amount": "1250.000001",
"event_ref": "log:0",
"execution_status": "success"
}
],
"transfers_truncated": false,
"aml_risk_level": "low",
"schema_version": "0.3",
"policy_version": "b2b-tx-2026-10.4",
"sanctions_hit": false,
"direct_sanctions_match": false,
"indirect_sanctions_exposure": false,
"risk_exposure": false,
"key_exposure": [],
"token_authenticity": "official",
"recipient_match": true,
"token_match": true,
"amount_match": false,
"coverage": "complete",
"workflow_coverage": "complete",
"source_coverage": {
"sanctions_sources": {
"ofac": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": 172800,
"scope": "configured_address_index",
"error_code": null
},
"eu": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:49:24Z",
"data_updated_at": "2026-09-22T18:01:34Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"uk": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-02T23:47:32Z",
"data_updated_at": "2026-10-02T00:00:00Z",
"stale_after_seconds": 3024000,
"scope": "configured_address_index",
"error_code": null
},
"un": {
"status": "not_applicable",
"checked_at": null,
"retrieved_at": null,
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "configured_address_index",
"error_code": null
}
},
"transaction_sources": {
"chain_explorer": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
},
"chain_node": {
"status": "checked",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_facts",
"error_code": null
}
},
"risk_sources": {
"aml_provider": {
"status": "checked_freshness_unknown",
"checked_at": "2026-10-10T09:00:00Z",
"retrieved_at": "2026-10-10T09:00:00Z",
"data_updated_at": null,
"stale_after_seconds": null,
"scope": "transaction_risk_score",
"error_code": null
}
},
"universal_clearance": false
},
"freshness": {
"checked_at": "2026-10-10T09:00:00Z",
"transaction_at": "2026-10-10T09:00:00Z",
"risk_data_at": "2026-10-10T09:00:00Z",
"token_data_at": "2026-10-10T09:00:00Z",
"max_source_age_seconds": 0
},
"overall_state": "REVIEW",
"environment": "live",
"reasons": [
{
"code": "EXPECTED_AMOUNT_MISMATCH",
"category": "expected",
"severity": "warning"
},
{
"code": "TX_FACTS_VERIFIED",
"category": "transaction",
"severity": "info"
},
{
"code": "TX_FINALIZED",
"category": "transaction",
"severity": "info"
},
{
"code": "AML_LOW",
"category": "risk",
"severity": "info"
},
{
"code": "NO_DIRECT_SANCTIONS_MATCH",
"category": "sanctions",
"severity": "info"
}
],
"decision_id": null,
"direction": null,
"workflow_type": null,
"versions": {
"decision": "b2b-tx-2026-10.4",
"rules": {
"exposure": "b2b-exp-v2",
"sanctions_freshness": "sf-v1",
"billing": "final_answers_only",
"integrity": "int-v3",
"reuse": "reuse-v1",
"allocation": "alloc-v1"
},
"reason_codes": "rc-1",
"evidence_schema": "ev-1",
"contract": "0.3"
},
"transaction_status": "CONFIRMED",
"integrity_status": "MISMATCH",
"risk_status": "NO_MATERIAL_SIGNAL",
"coverage_status": "OK",
"status_drivers": {
"transaction": "TX_FINALIZED",
"integrity": "EXPECTED_AMOUNT_MISMATCH",
"risk": null,
"coverage": null,
"action": "EXPECTED_AMOUNT_MISMATCH"
},
"result_final": true,
"verification_final": true,
"risk_final": true,
"risk_retryable": false,
"risk_retry_after_seconds": null,
"retryable": false,
"retry_after_seconds": null,
"recommended_action": "MANUAL_REVIEW",
"integrity": {
"status": "MISMATCH",
"selected_event_ref": "log:0",
"relevant_event_count": 1,
"comparisons": {
"recipient": {
"expected": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"actual": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
"result": "MATCH"
},
"sender": {
"expected": null,
"actual": "TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3",
"result": "NOT_EVALUATED"
},
"token": {
"expected": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"actual": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"result": "MATCH"
},
"amount": {
"expected": "1251.000001",
"actual": "1250.000001",
"result": "UNDERPAID",
"tolerance": null,
"delta": "-1",
"delta_raw": "-1000000"
},
"network": {
"expected": null,
"actual": "tron",
"result": "NOT_EVALUATED"
}
}
},
"risk": {
"status": "NO_MATERIAL_SIGNAL",
"driver": null,
"driver_evidence_ids": []
},
"evidence_items": [
{
"evidence_id": "ev_431b2fd74ad43ef5",
"kind": "transaction_facts",
"source": "chain_explorer",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_63c8c4e421f6ff66",
"kind": "transaction_facts",
"source": "chain_node",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "block:80000000",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-10T09:00:00Z",
"temporal_scope": "TRANSACTION_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_896f4ce46de5246c",
"kind": "aml_risk",
"source": "aml_provider",
"subject": {
"type": "transaction",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "transaction_risk_score",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked_freshness_unknown",
"freshness": {
"age_seconds": 0,
"stale": true,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_7d0537ae6c2054d5",
"kind": "sanctions_list",
"source": "ofac",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 172800
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_2be872923c0687c9",
"kind": "sanctions_list",
"source": "eu",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-09-22T18:01:34Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_df2204c780968cb5",
"kind": "sanctions_list",
"source": "uk",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": "2026-10-02T00:00:00Z",
"temporal_scope": "LIST_PUBLICATION",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": 3024000
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_76c33d7fb3a48fb7",
"kind": "sanctions_list",
"source": "un",
"subject": {
"type": "transaction_addresses",
"ref": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"source_reference": "configured_address_index",
"observed_at": null,
"effective_at": null,
"temporal_scope": "LIST_PUBLICATION",
"coverage": "not_applicable",
"freshness": {
"age_seconds": null,
"stale": false,
"stale_after_seconds": null
},
"dependency": "not_applicable",
"disagreement": null,
"evidence_version": "ev-1"
},
{
"evidence_id": "ev_81b44db3a9445d39",
"kind": "token_authenticity",
"source": "token_registry",
"subject": {
"type": "token",
"ref": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
},
"source_reference": "official",
"observed_at": "2026-10-10T09:00:00Z",
"effective_at": null,
"temporal_scope": "CHECK_TIME",
"coverage": "checked",
"freshness": {
"age_seconds": 0,
"stale": false,
"stale_after_seconds": null
},
"dependency": "required",
"disagreement": null,
"evidence_version": "ev-1"
}
],
"coverage_limitations": {
"runtime": [],
"product": [
"AML_TRANSACTION_LEVEL_ONLY",
"RISK_STATE_AS_OF_CHECK",
"SANCTIONS_CONFIGURED_LISTS_ONLY"
]
},
"obligation": null,
"reuse": null
}
Zero-Friction v0.1
POST /v1/check adds optional network context and a short response. A request with an explicit network never switches chains. NETWORK_REQUIRED and NETWORK_AMBIGUOUS require a corrected body and a new idempotency key; a replay keeps the original network and result. Short cURL, Node.js, Python and PHP examples, address normalization and the asset matrix are in the linked guide.
Wallet check
POST /v1/wallet/check uses the same retry loop with a 35-second client deadline and a wallet body; the guide carries the cURL, Python and TypeScript snippets.
Transaction states
transaction_state describes what the chain reports about the transaction. It does not replace the risk assessment or the coverage check.
transaction_state is the 0.2 field, in lowercase, and keeps unknown for facts that cannot establish a state. Contract 0.3 answers the same question in transaction_status (CONFIRMED, PENDING, FAILED, NOT_FOUND, INSUFFICIENT, where INSUFFICIENT covers unknown, sources that disagree on the transaction itself (the hash they returned, whether it exists, its block, its execution status or its finality) and an absence not every source confirmed; a disagreement only about its content (transfers, sender, recipient or transaction type) keeps transaction_status and shows as coverage_status: DISAGREEMENT with verification_final: false), which also applies the finality threshold: a confirmed transaction below it is PENDING. Prefer transaction_status; see status axes.
| State | Meaning | Integration behavior |
|---|---|---|
confirmed |
Chain facts report confirmation. | Also require sufficient confirmations and examine the overall state and coverage. |
pending |
The transaction is visible but finality is incomplete. | Do not record final settlement. The answer is not charged. Schedule a separately identified later observation with a new idempotency key, with backoff: for TRON, finality takes about a minute after broadcast. Free answers count toward the daily ceiling of unbilled checks (see limits). |
failed |
Execution failed or reverted. | Do not treat the expected transfer as received. |
not_found |
The queried transaction was not found in the available evidence. | Check the network and hash; absence is not proof of a completed payment. |
unknown |
The available transaction facts cannot establish a state. | Treat as incomplete evidence. |
TRON confirmations
TRON v1 uses a 19-confirmation finality policy together with finalized chain evidence. Compare confirmations with required_confirmations. A transaction state alone does not establish risk coverage. Response examples illustrate these states.
Ethereum and TON finality
Ethereum requires a canonical block at or below the finalized head from the configured sources; the latest head or any block before the finalized head is insufficient. TON requires provider-attested masterchain finality for every transaction and, separately, a complete message trace. The value 1 in required_confirmations for these adapters does not replace either finality policy. See network details.
Overall states
overall_state combines the transaction facts, the risk, sanctions and token checks and the expected payment comparison into one state.
| State | Meaning |
|---|---|
CLEAR |
Applicable checks completed without an identified issue and finality requirements were met. This is not a guarantee against future risk. |
REVIEW |
The result contains a condition requiring review, such as pending finality, failed execution, elevated risk or an expected-payment mismatch. |
HIGH_RISK |
A high or critical finding exists, such as a sanctions match, high AML risk or a fake token. |
LIMITED_DATA |
Evidence is incomplete, unsupported or contradictory. Never treat this as CLEAR. |
Contract 0.3 also answers the four underlying questions separately, says whether the answer is final and recommends an action: see status axes and recommended action. overall_state keeps the rules below; ledger and client-context findings (another obligation already paid by this transaction, a duplicate execution, an already credited deposit) can only raise it to REVIEW.
On contract 0.3, decide on the axes, not on this state. overall_state is a one-word summary kept for 0.2 integrations, and missing data outranks a mismatch in it: a payment that is definitively wrong (verification_final: true, integrity_status: MISMATCH) still reads LIMITED_DATA when the risk screen could not run. Use verification_final and integrity_status for the payment, and risk_status and recommended_action for what to do with it.
Act on the state
The state is a check result, not a payment instruction: your policy decides. The design-partner pilot agrees this mapping:
| Answer | Recommended action |
|---|---|
CLEAR, coverage: complete, every requested *_match is true |
Eligible for crediting under your own policy. |
REVIEW |
Manual review. TX_PENDING_CONFIRMATIONS: wait and check again with a new key. EXPECTED_*_MISMATCH: the payment is not the one you expected; these codes never appear while transaction_status is PENDING. |
HIGH_RISK |
Hold the funds and escalate to compliance. |
LIMITED_DATA |
No automatic credit. With verification_final: true and integrity_status: MISMATCH the payment is definitively wrong: review it, a retry will not change it. Otherwise retry later with a new key; after a bounded number of attempts, review manually. While the sources disagree about the transaction itself, the answer is not final and can still carry EXPECTED_*_MISMATCH (see statuses). |
429, 5xx, 409 idempotency_in_progress |
Retry with the same idempotency key after Retry-After. |
404 transaction_not_found (/v1/check) |
Check the hash; look again later with a new key. |
422 NETWORK_REQUIRED, 422 NETWORK_AMBIGUOUS |
Resend with network and a new key. |
Other 4xx |
Integration error: fix the request, do not retry. |
Read the state together with coverage
Coverage and state are independent. A known sanctions match, fake token or high AML finding takes priority as HIGH_RISK even when facts are incomplete or contradictory. Without such a finding, missing required evidence gives LIMITED_DATA. /v1/check reports the same states in lowercase in state and provides all reason objects in details.reasons.
Status axes and recommended action
Contract 0.3 answers four separate questions about a transaction instead of folding them into one state. Each answer has its own status and the reason code that set it. overall_state is still returned, computed by the 0.2 rules, so an integration built on it keeps working.
Four axes
| Field | Values | Question |
|---|---|---|
transaction_status |
CONFIRMED, PENDING, FAILED, NOT_FOUND, INSUFFICIENT |
Did the transaction execute, and is that final? |
integrity_status |
MATCH, MISMATCH, AMBIGUOUS, NOT_EVALUATED, INSUFFICIENT |
Does it pay what you expected? |
risk_status |
NO_MATERIAL_SIGNAL, REVIEW, HIGH_RISK, INSUFFICIENT, NOT_EVALUATED |
Is a material risk or sanctions signal attached to it? |
coverage_status |
OK, DEGRADED, SKIPPED, UNAVAILABLE, DISAGREEMENT |
Did the sources this answer needs respond, and agree? |
status_drivers names the reason code behind each axis and behind recommended_action (transaction, integrity, risk, coverage, action); null means nothing needed explaining. When recommended_action is MANUAL_REVIEW, status_drivers.action names one finding: TX_REVERTED on a FAILED transaction, otherwise the most severe finding. Among findings of equal severity, what the chain shows about the transaction itself comes first, then the risk screens (AML, sanctions, token), then the payment comparison and the remaining findings. So when a final payment mismatch is checked while the AML source is unavailable, status_drivers.action usually shows AML_UNAVAILABLE, not the mismatch: read status_drivers.integrity and reasons for the payment comparison, and each axis's own driver for its cause.
Transaction
CONFIRMED: executed and past the network's finality threshold.PENDING: in the mempool or a block, but below the finality threshold. Never final.FAILED: executed and reverted. When no transfer in it executed, nothing was paid; on TON a failed trace can still contain a leg that did execute, so readintegrity_statusandrecommended_action.NOT_FOUND: every source confirms that the transaction is absent. It may still appear.INSUFFICIENT: the sources could not establish the facts, or disagree on whether the transaction exists, on its status or on its finality.
Integrity
MATCH: after chain finality, exactly one executed transfer pays the expected recipient the expected token and amount, withinamount_tolerancewhen you send one. Legs inside one transaction that add up to the amount also match (SPLIT_WITHIN_TX).MISMATCH: no executed transfer fits.integrity.comparisonsshows which field differs and, for the amount,UNDERPAIDorOVERPAIDwith thedelta.AMBIGUOUS: several executed transfers fit equally well; nothing is allocated.NOT_EVALUATED: the transaction is pending, you sent nothing to compare, or the transaction failed and nothing in it executed (a reverted token call usually leaves no transfer rows at all).INSUFFICIENT: you sent expectations but the transfer data needed to compare them is missing, the sources disagree about the transfers, the obligation you named has no instruction on record (INSTRUCTION_UNAVAILABLE), or the transaction failed while a transfer in it executed (a TON trace), so whether it paid is not established by the chain alone.
A movement that did not execute never matches: a reverted transfer to the right address is NOT_EVALUATED, and its recipient_match, token_match and amount_match are null.
Risk
HIGH_RISK beats REVIEW, which beats INSUFFICIENT. NO_MATERIAL_SIGNAL means the applicable screens ran and found nothing material; it is not a clearance. NOT_EVALUATED means risk does not apply (a failed or absent transaction). The risk block repeats the status with its driver and driver_evidence_ids, the evidence items the driver rests on. Every provider exposure row in key_exposure carries the grade the exposure policy gave it.
Coverage
DISAGREEMENT beats UNAVAILABLE (a required group of sources did not answer), which beats DEGRADED (one chain source only, a stale list, an asset without AML support), then SKIPPED (risk sources not called because the transaction failed or is absent) and OK.
Verification and risk finality
verification_final describes the payment facts and comparison. result_final is its alias; retryable is its opposite, and retry_after_seconds is the suggested wait for another verification observation. A final chain transaction with an exact expected match returns verification_final: true and integrity_status: MATCH even when KYT is unavailable and risk_status: INSUFFICIENT.
risk_final is true once checking again is not expected to fill a gap in the risk assessment: the transaction is final, its sources agree, and no AML, sanctions or token check had a temporary gap (an outage or a stale list). While the transaction is pending or not found, risk_final is false whatever risk_status says, and risk_retry_after_seconds equals retry_after_seconds: risk is assessed again once the transaction is final. risk_retryable is its opposite; risk_retry_after_seconds suggests when to check risk again. A permanent coverage limit can be final while remaining INSUFFICIENT: finality does not mean clearance. KYT describes risk at check time and can change later even after a final assessment.
Pending transactions return integrity_status: NOT_EVALUATED, verification_final: false, null match flags, NOT_EVALUATED for every requested comparison and no EXPECTED_*_MISMATCH reason: terms that differ are reported only once the transaction is final. When the sources disagree about the transaction itself (transaction_status: INSUFFICIENT, coverage_status: DISAGREEMENT), the answer is not final either, but it still compares the transfers the sources report and can carry EXPECTED_*_MISMATCH: act on verification_final: false and check again. Observed transfers remain evidence, not a final payment match. Verification retries wait 5–120 seconds for pending finality, 15 seconds for an absent transaction, or 30 seconds for a temporary chain-source gap. A temporary KYT gap suggests a separate risk retry after 30 seconds. When the AML source reports error_code spend_cap (your organization's daily cap on paid sources is reached, or spend cannot be accounted for the moment) or daily_cap (the AML source's service-wide daily ceiling is reached), a reached cap resets at 00:00 UTC, and a new check before then usually returns the same gap; see limits. On a transaction that is not found, risk_retryable is true although risk_status is NOT_EVALUATED: risk is assessed once the transaction appears.
Missing KYT does not reopen final verification and never permits PROCEED: MATCH with risk_status: INSUFFICIENT recommends MANUAL_REVIEW. Only final answers with complete coverage are charged; a final verification with partial KYT coverage remains free. For a new observation, use a new Idempotency-Key; replaying the same key returns the stored answer under its original policy.
Recommended action
recommended_action is what the answer supports, not an instruction. Your policy decides, and you record what you did on the decision.
| Value | When |
|---|---|
HOLD_AND_ESCALATE |
risk_status: HIGH_RISK. |
RECHECK_LATER |
Verification is not final: pending, absent, a temporary chain-source gap or disagreement. A check sent with direction: "OUTGOING" whose transaction is not found adds ATTEMPT_MAY_STILL_LAND. |
NOT_EXECUTED |
The transaction failed and no transfer in it executed. A failed transaction in which some leg executed is MANUAL_REVIEW, never a go-ahead. |
MANUAL_REVIEW |
A reviewable finding: risk_status: INSUFFICIENT, REVIEW risk, MISMATCH, AMBIGUOUS, INSUFFICIENT integrity, reuse by another obligation, a duplicate execution or an already credited deposit. |
CONFIRM_INTERNAL_STATE |
The chain is in order, but ChainZap cannot see your side: no obligation was named, the payment is not known to be outgoing, nothing was compared, or customer_context does not say NOT_CREDITED. Check your own records before acting. |
PROCEED |
A clean match against a recorded outgoing obligation with a clean ledger, or a payment you declare NOT_CREDITED. |
An incoming payment is never PROCEED unless you send customer_context.credit_status: "NOT_CREDITED"; CREDITED raises the answer to REVIEW with ALREADY_CREDITED, and an allocation_status of UNKNOWN keeps it at CONFIRM_INTERNAL_STATE. When a check omits direction, it is taken from the obligation's recorded direction, then from workflow_type: PAYOUT and REFUND are outgoing, DEPOSIT and INVOICE incoming. Without customer_context.credit_status: "NOT_CREDITED", a payment whose direction is still unknown is never PROCEED.
Evidence and limitations
evidence_items lists what the answer rests on: chain sources, the AML provider, each sanctions list and the token check. Each item has evidence_id, kind, a neutral source, subject, source_reference (such as the block), observed_at (when ChainZap read it), effective_at (the time the fact refers to, such as the block time or the list date), coverage, freshness, dependency (required, or not_applicable when the source does not apply to this transaction), evidence_version and, when sources disagree, disagreement.fields. AML items carry temporal_scope: "CHECK_TIME": the provider reports the risk state as of the check, not as of the payment.
coverage_limitations separates what limited this answer (runtime) from what the product never covers for this network or asset (product, for example AML_TRANSACTION_LEVEL_ONLY or SANCTIONS_CONFIGURED_LISTS_ONLY). A product limitation does not make an answer retryable.
Versions
versions names everything that shaped the answer: decision (equal to policy_version), rules (exposure, sanctions freshness, billing, integrity, reuse and allocation rules), reason_codes, evidence_schema and contract. Store it with the decision if you need to explain the answer later.
Data completeness
Complete and partial
coverage: complete means the applicable evidence checks met their requirements for this response. It does not mean the transaction is free of risk; a complete check can still report HIGH_RISK. coverage: partial means one or more required sources, asset mappings, token checks or transaction facts are missing, unsupported or inconsistent.
workflow_coverage reports completion of this check; coverage is its compatibility alias. complete never means universal compliance clearance. source_coverage.sanctions_sources reports OFAC/EU/UK/UN separately: checked, checked_stale, checked_freshness_unknown, not_checked, not_applicable or unavailable. In source_coverage.risk_sources, checked_freshness_unknown is the normal status of a completed AML screen: the AML source does not date its data, so its evidence item also reads freshness.stale: true. This does not make the check partial.
Sanctions list freshness
Each sanctions list is judged by its own freshness window (policy sf-v1, part of policy_version). These are internal policies, not provider guarantees:
| List | Fresh while | Basis |
|---|---|---|
| OFAC | 48 hours | The last successful sync with the mirror of the SDN list. retrieved_at reports it; the SDN publication date is not available, so data_updated_at is null. |
| EU, UK | 35 days | The last rebuild from the official publication, done monthly. data_updated_at is the publication date, retrieved_at the rebuild. |
| UN | not_applicable |
The UN Security Council list publishes no crypto addresses. |
A list that is stale, whose freshness cannot be established, or that is unavailable cannot back a clean answer: the check reports SANCTIONS_DATA_STALE or SANCTIONS_UNAVAILABLE, coverage: partial and LIMITED_DATA, and is not charged. A known high-risk finding still wins. stale_after_seconds on each source states its window.
direct_sanctions_match means an exact address match in the configured indexes. false means no match in those indexes, subject to their scope and freshness. indirect_sanctions_exposure means the transaction risk provider reported sanctions exposure of any size, including counterparty exposure that the provider labels “direct”; it is not proof that a transaction party is listed. risk_exposure reports other exposure categories of any size or a hacking event. The deprecated sanctions_hit is an alias of direct_sanctions_match only. If the AML source is unavailable, exposure flags are null; completed local matching can still be false.
How exposure moves the state
The two exposure flags say that the provider reported something; whether it moves the state depends on how close and how large it is (policy b2b-exp-v2). The reported rows stay in key_exposure (up to 50, after any local list match), most significant first, with their hops, share and the grade the policy gave each one (high, review, minor). percent is null when the share is unknown or its source does not allow showing it.
| Provider row | Hops and share | Effect |
|---|---|---|
| Sanctioned entity | 1 hop or closer and at least 5% | HIGH_RISK, INDIRECT_SANCTIONS_EXPOSURE |
| Sanctioned entity | 1 hop or closer below 5%, at least 1% at any hop, or share unknown | REVIEW, SANCTIONS_EXPOSURE_REVIEW |
| Sanctioned entity | 2 hops or more and below 1% | no change, SANCTIONS_EXPOSURE_MINOR |
| Other category | up to 2 hops, with at least 1% or an unknown share; any hacking event | REVIEW, RISK_EXPOSURE |
| Other category | further away or smaller | no change, RISK_EXPOSURE_MINOR |
| Unrecognised or empty category | as for other categories | REVIEW, UNRECOGNIZED_PROVIDER_LABEL; or no change, UNRECOGNIZED_PROVIDER_LABEL_MINOR |
A category ChainZap does not recognise is never ignored: it is graded like any other risk category and named, so a close or large unfamiliar finding goes to review, and a distant, small one is still reported (UNRECOGNIZED_PROVIDER_LABEL_MINOR). The recognised categories are sanctioned_entity, illicit_activity, mixer, risk_exchange, gambling and bridge.
The thresholds were calibrated on a sample of ordinary USDT transfers on TRON: under the earlier rule, which escalated any indirect sanctions trace, most of them were HIGH_RISK; under this one risk_status: HIGH_RISK rests on an exact list match, a material share one hop away or a high AML level, and risk.driver names which. An exact local sanctions match of a transaction party is always HIGH_RISK. Apply your own stricter rule to key_exposure if your compliance policy requires one.
Each source reports checked_at (this evaluation), retrieved_at (when a response or remote index was fetched) and data_updated_at (the underlying list date, when known). A recent fetch does not establish a recent underlying publication. The AML source does not provide that publication date; it remains null. The legacy freshness.max_source_age_seconds covers fetched observations only, not sanctions-list age. source_coverage.universal_clearance is always false.
- Risk unknown:
aml_risk_level="unknown". - Token unverified:
token_authenticity="unknown"; its ticker does not prove authenticity.
LIMITED_DATA is a normal business response with HTTP 200, not necessarily a transport error.
Freshness
Read freshness.checked_at, the evidence timestamps and max_source_age_seconds. A source timestamp of null means the time is unknown. An idempotent replay returns the original result and the original request ID; it is not a fresh observation. A new observation is a new logical operation, created after you have resolved the previous response.
Billing
Only complete, final checks are charged: CLEAR, REVIEW and HIGH_RISK with coverage: complete for a transaction confirmed past its finality policy or failed for good each use one check. Pending and not-found answers, partial coverage (LIMITED_DATA), transport errors, timeouts and idempotent replays do not use a check; their reservation is released. The Playground page uses the same rule and the same organization quota. Sandbox keys never use paid checks. Details are in plans and payment.
Network and asset boundaries
See the Ethereum/TON asset matrix and finality policies. Complete coverage is scoped to the supported transfer type and the selected asset; it does not cover untraced ETH internal value or a token's net balance effect. Unknown token decimals never become a default value.
TON contract value that cannot be classified produces TON_CONTRACT_VALUE_NOT_CLASSIFIED and partial coverage, even if another transfer in the same trace is recognized. It cannot produce CLEAR; a known high-risk finding still takes priority as HIGH_RISK. Check details.limitations, details.finalized and details.trace_complete in the short response.
A TON jetton credit can be confirmed even when the recipient wallet cannot execute a notification because it has too little gas. TON_NOTIFICATION_NOT_EXECUTED records this separately: the jetton transfer and the wallet owner must still be verified by both sources. It does not excuse a failed or bounced token transfer.
source_coverage.transaction_sources reports each configured on-chain fact source separately under a stable neutral name: chain_explorer and chain_node on TRON and TON, chain_node and chain_node_secondary on Ethereum. source_coverage.risk_sources.aml_provider is the AML assessment. These observations retain their original retrieval time through the facts cache. A successful response with an unknown AML risk level is a partial aml_provider observation (risk_level_unknown). Missing local sanctions coverage does not turn a successful AML assessment into AML_UNAVAILABLE; the workflow remains partial with SANCTIONS_UNAVAILABLE. Network availability still depends on deployment configuration and tenant access.
Wallet checks
A wallet check reports its own coverage word in details.data_coverage: FULL when every applicable module was fully screened, PARTIAL when at least one was screened only in part, INSUFFICIENT when a gate module (sanctions_aml or address_security) was not screened at all or the engine could not decide. The top-level coverage is complete only for FULL. Each module row carries its own source_coverage, and details.source_coverage lists every source with the same status vocabulary as above. Unlike the transaction check, a wallet check is charged whenever a state is produced, including with partial coverage; only limited_data is free. See wallet check.
Coverage status and evidence items
Contract 0.3 adds coverage_status (OK, DEGRADED, SKIPPED, UNAVAILABLE, DISAGREEMENT), the reason behind it in status_drivers.coverage, one evidence_items entry per source the answer rests on, and coverage_limitations split into what limited this check and what the product never covers. See status axes. coverage and workflow_coverage keep their meaning.
Reason codes
Each reason has code, category and severity (info, warning, high, critical). /v1/transaction/check returns 2 to 5 prioritized reasons; the short list always keeps the reason that decided the state, every EXPECTED_* reason, every payment comparison and client-context finding, and every obligation ledger finding above info, and fills the rest by severity. The full catalogue is versioned (versions.reason_codes); status_drivers names the reason behind each status axis. /v1/check returns the full list in details.reasons and the corresponding strings in reason_codes. Tolerate future codes. Never treat an unknown code as a clean result, and never infer from an omitted reason that the related check was performed.
| Code | Meaning |
|---|---|
TX_FACTS_VERIFIED |
The transaction sources answered and agree, including when they agree that the transaction is absent. It describes the facts, not a found or matching payment. |
TX_FACTS_PARTIAL |
Required transaction facts are incomplete. |
TX_FACTS_DISAGREE |
Transaction evidence is contradictory. |
TX_FINALIZED |
Transaction finality requirements are met. |
TX_PENDING_CONFIRMATIONS |
Finality or confirmations are insufficient. |
TX_REVERTED |
Transaction execution failed. |
TX_NOT_FOUND |
The transaction was not found. |
TRANSFERS_TRUNCATED |
Transfer evidence was truncated. |
AMBIGUOUS_TRANSFER |
Several transfers fit the supplied recipient and token, and none, or more than one, can be selected as the payment. |
AML_UNSUPPORTED_ASSET |
The applicable asset lacks supported AML coverage. |
AML_UNAVAILABLE |
Applicable AML evidence is missing. |
AML_LOW |
Available AML assessment reports low risk. |
AML_ELEVATED |
Available AML assessment reports moderate risk. |
AML_HIGH |
Available AML assessment reports high or severe risk. |
DIRECT_SANCTIONS_MATCH |
Exact address match in the configured sanctions indexes. |
NO_DIRECT_SANCTIONS_MATCH |
No exact address match in the checked indexes; read source coverage and freshness. |
INDIRECT_SANCTIONS_EXPOSURE |
Material provider-reported sanctions exposure (1 hop or closer, at least 5%); not a direct listing match. Gives HIGH_RISK. |
SANCTIONS_EXPOSURE_REVIEW |
Provider-reported sanctions exposure that needs review (1 hop or closer below 5%, at least 1% at any hop, or share unknown). Gives REVIEW. |
SANCTIONS_EXPOSURE_MINOR |
Distant and small provider-reported sanctions exposure; reported, does not change the state. |
RISK_EXPOSURE |
Significant other risk exposure reported by the provider (up to 2 hops and at least 1%, or share unknown), or a hacking event. Gives REVIEW. |
RISK_EXPOSURE_MINOR |
Distant or small other risk exposure; reported, does not change the state. |
SANCTIONS_UNAVAILABLE |
Sanctions screening is unavailable; this is not a clear result. |
SANCTIONS_DATA_STALE |
A sanctions list is past its freshness window or its freshness cannot be established; coverage is partial. |
TOKEN_AUTH_UNAVAILABLE |
Token authentication evidence is unavailable. |
TOKEN_OFFICIAL |
Token contract is recognized as official. |
TOKEN_FAKE |
Token is identified as fake. |
TOKEN_UNKNOWN |
Token authenticity is unknown. |
EXPECTED_RECIPIENT_MISMATCH |
The selected transfer does not match the expected recipient. |
EXPECTED_TOKEN_MISMATCH |
The selected transfer does not match the expected contract. |
EXPECTED_AMOUNT_MISMATCH |
The selected transfer does not match the expected raw amount. |
EXPECTED_DATA_UNAVAILABLE |
A requested comparison could not be completed because transfer data is missing. Its match field is null. |
EXPECTED_SENDER_MISMATCH |
The selected transfer does not come from expected_sender. |
EXPECTED_NETWORK_MISMATCH |
The recorded instruction names another network than the one checked. |
AMOUNT_WITHIN_TOLERANCE |
The amount differs from the expected one by no more than amount_tolerance; it matches. |
ADDITIONAL_RELEVANT_TRANSFERS |
Besides the matching transfer, the transaction pays the expected recipient the expected token again; it may pay twice. Gives REVIEW. |
SPLIT_WITHIN_TX |
Several transfers in the transaction to the expected recipient add up to the expected amount. Gives REVIEW. |
ATTEMPT_MAY_STILL_LAND |
A check sent with direction: "OUTGOING" found no transaction yet; the attempt behind it may still reach the chain. Do not pay it again before it is final. |
UNRECOGNIZED_PROVIDER_LABEL |
The AML provider reported a category ChainZap does not recognise, close and large enough to look at. Gives REVIEW. |
UNRECOGNIZED_PROVIDER_LABEL_MINOR |
An unrecognised provider category that is distant or small; reported, does not change the state. |
Obligation ledger and client context
These reasons appear when a check names an obligation or carries customer_context. They never change coverage or what is charged.
| Code | Meaning |
|---|---|
INSTRUCTION_UNAVAILABLE |
The obligation named has no instruction on record for the version asked; nothing was compared. integrity_status: INSUFFICIENT, gives REVIEW. |
INSTRUCTION_HISTORY_INCOMPLETE |
The first instruction recorded for the obligation is not version 1; earlier versions are unknown. |
INSTRUCTION_NOT_EFFECTIVE |
The payment is in a block before the instruction's instruction_effective_at. Gives REVIEW. |
INSTRUCTION_CONFLICT |
Another request changed the obligation's instruction while this one was being checked. Gives REVIEW. |
TX_REUSED_ACROSS_OBLIGATIONS |
The payment event already settles a different obligation. Gives REVIEW; nothing is allocated. |
DUPLICATE_EXECUTION |
Two or more transactions together paid the obligation more than it was owed. Gives REVIEW. |
EVENT_CONTENT_CHANGED |
A payment event recorded earlier is now reported with different content; the record is not overwritten. Gives REVIEW. |
ALREADY_CREDITED |
You declared the payment already credited, or applied in your books, even in part (customer_context). Gives REVIEW. |
CUSTOMER_STATE_UNKNOWN |
Shown as status_drivers.action when ChainZap cannot tell whether acting on a clean answer is safe for your books: CONFIRM_INTERNAL_STATE. |
Product limitations
Listed in coverage_limitations.product, never in reasons: what the product does not cover for this network or asset, whatever the check. They do not make an answer retryable.
| Code | Meaning |
|---|---|
AML_TRANSACTION_LEVEL_ONLY |
AML screening covers the transaction's addresses as the provider sees them, not the full history of every counterparty. |
RISK_STATE_AS_OF_CHECK |
Risk evidence is the provider's state at the time of the check, not at the time of the payment. |
SANCTIONS_CONFIGURED_LISTS_ONLY |
Sanctions matching covers the configured lists only (OFAC, EU, UK). |
MEMO_NOT_EVALUATED |
A memo or comment on the transfer, such as a TON comment, is not compared. |
Ethereum / TON / Zero-Friction
/v1/check exposes all reason objects in details.reasons and string codes in reason_codes. The canonical /v1/transaction/check keeps its bounded list.
| Code | Meaning |
|---|---|
ETH_REORG_DETECTED |
Canonical Ethereum block does not match transaction inclusion. |
ETH_NATIVE_INTERNAL_TRANSFERS_UNAVAILABLE |
Native internal ETH value is outside the receipt-log scope. |
TOKEN_MINT_OR_BURN |
A mint or burn is not an ordinary deposit. |
TOKEN_BALANCE_EFFECT_NOT_VERIFIED |
Logs do not prove net token balance changes. |
ZERO_VALUE_TRANSFER |
Transfer amount is zero. |
TON_BOUNCED |
A message was bounced. |
TON_TRACE_INCOMPLETE |
Required message descendants or complete trace evidence are missing. |
TON_EXECUTION_FAILED |
A transaction in the transfer trace failed. |
TON_FINALITY_UNVERIFIED |
Masterchain finality is not verified. |
TON_CONTRACT_VALUE_NOT_CLASSIFIED |
Contract-message TON value is not classified as a plain transfer. Coverage is partial even if another transfer was verified. |
JETTON_IDENTITY_UNVERIFIED |
Jetton wallet/master/owner identity is unverified. |
JETTON_WALLET_MISMATCH |
Jetton wallet, master or owner contradicts the transfer message. |
NO_SUPPORTED_TRANSFER |
No supported completed transfer was established. |
MULTI_ASSET_AML_PARTIAL |
Multiple assets are present; one asset rail was screened for AML. |
TON_TRACE_LIMIT_EXCEEDED |
The bounded trace size or depth was exceeded; transfer evidence is incomplete. |
TON_NOTIFICATION_NOT_EXECUTED |
A jetton transfer notification reached a recipient that did not execute it; the transfer itself completed. |
Wallet reason codes
POST /v1/wallet/check returns up to ten reasons in details.reasons, ordered by severity, and their codes in reason_codes. A finding is stated only when the engine's own significance policy rates it as one, so a reason here always corresponds to something the report would show. The severity in the table is the default; a confirmed critical provider flag or a red explorer tag raises it.
| Code | Category / severity | Meaning |
|---|---|---|
DIRECT_SANCTIONS_MATCH |
sanctions / critical |
Exact address match in the configured sanctions indexes, or a direct listing reported by the AML provider. |
INDIRECT_SANCTIONS_EXPOSURE |
sanctions / high |
Exposure to sanctioned funds reported by the AML provider; not a direct listing. |
SANCTIONS_EXPOSURE_MINOR |
sanctions / warning |
A small share of exposure to sanctioned funds reported by the AML provider. The transaction check emits the same code at info. |
SANCTIONS_UNAVAILABLE |
sanctions / warning |
No sanctions index was screened; this is not a clear result. |
NO_DIRECT_SANCTIONS_MATCH |
sanctions / info |
No exact match in the screened indexes; read source coverage and freshness. |
AML_HIGH |
risk / high |
The AML provider reports high or severe risk. |
AML_ELEVATED |
risk / warning |
The AML provider reports moderate risk. |
AML_LOW |
risk / info |
The AML provider reports low risk. |
AML_EXPOSURE_UNAVAILABLE |
risk / warning |
The AML provider was called but did not answer; exposure is unknown. |
AML_EXPOSURE_SKIPPED |
risk / info |
The AML provider was not called because a local sanctions or denylist hit already decides the result. |
HACKING_EVENT_LINK |
risk / high |
The AML provider links the address to a known hacking event. |
DENYLIST_MATCH |
address / critical |
The address is on a public denylist of scam, phishing or drainer addresses. |
ISSUER_BLOCKED |
address / critical |
A stablecoin issuer has frozen the address. |
PROVIDER_SECURITY_FLAG |
address / high |
A security provider flags the address; the severity follows the confirmed flags. |
EXPLORER_RISK_TAG |
address / high |
A block explorer or account label marks the address as risky. |
SCAM_EVENT_ACTIVITY |
address / high |
Transfers with addresses flagged for scam activity were observed. |
ADDRESS_SECURITY_UNAVAILABLE |
address / warning |
Address security sources were not fully screened. |
NO_ADDRESS_SECURITY_FLAGS |
address / info |
The screened address security sources report nothing. |
TOKEN_IMPERSONATION |
token / high |
A held or created token impersonates an official asset. |
TOKEN_HOLDINGS_UNVERIFIED |
token / warning |
Held tokens could not all be screened for authenticity. |
TOKEN_HOLDINGS_VERIFIED |
token / info |
Held tokens were screened and none impersonates an official asset. |
RISKY_COUNTERPARTY_DIRECT |
counterparties / high |
A direct counterparty is a known risky service or address. |
RISKY_COUNTERPARTY_INDIRECT |
counterparties / warning |
A risky service or address sits one hop further away. |
COUNTERPARTY_SCREENING_PARTIAL |
counterparties / warning |
Not every counterparty could be attributed; coverage is partial. |
NO_COUNTERPARTY_FLAGS |
counterparties / info |
Screened counterparties raised no flags. |
NEW_WALLET |
behaviour / warning |
The wallet is very new. |
BEHAVIOUR_PATTERN_FLAGGED |
behaviour / warning |
A transaction pattern worth a look was observed, for example bursts, rapid cycling or relay behaviour. |
LOW_ACTIVITY |
behaviour / info |
Very few transactions; behaviour signals carry little weight. |
CONTRACT_ADDRESS |
behaviour / info |
The address is a contract, not a wallet. |
NO_BEHAVIOUR_FLAGS |
behaviour / info |
No notable behaviour pattern was observed. |
WALLET_DATA_LIMITED |
coverage / warning |
Not enough data to decide; the state is limited_data. |
SOURCE_UNAVAILABLE |
coverage / warning |
A required source did not answer. |
NETWORK_ASSUMED_ETH |
coverage / warning |
A 0x address was screened on Ethereum only; it may also exist on other EVM chains. |
Decisions, actions and outcomes
Every transaction check is a decision with its own decision_id. What ChainZap recommended, what you did, how you resolved it and how it turned out are separate records: a recommendation is not an action, and a held payment is not a prevented loss until you confirm it was one.
Read a decision
GET /v1/decisions/{decision_id} returns the decision as it was made: the four status axes, overall_state, recommended_action, reuse_status, the selected payment event, reason_codes, versions and the evidence_items it rested on, plus every event recorded on it since. A later check of the same transaction is a new decision; it never rewrites an earlier one, so an answer you acted on can always be explained with the evidence it had at the time. Evidence items are kept for as long as the providers' terms allow and at most the retention period of raw values.
An idempotent replay of the original request also returns the original answer, byte for byte.
Record what followed
| Endpoint | Body | Meaning |
|---|---|---|
POST /v1/decisions/{decision_id}/actions |
action, optional action_at |
What you did: CREDITED, PAID, HELD, REJECTED, REFUNDED, ESCALATED, RETRIED, NO_ACTION, OTHER. |
POST /v1/decisions/{decision_id}/resolution |
resolution, optional resolved_at |
How the case was closed: ACCEPTED, ACCEPTED_AFTER_REVIEW, REJECTED, REFUNDED, CORRECTED, WRITTEN_OFF, OTHER. |
POST /v1/decisions/{decision_id}/outcome |
outcome_status, loss_prevented, optional outcome_at |
How it turned out: CONFIRMED, DISPUTED, UNRESOLVED or UNKNOWN, and whether a loss was prevented: CONFIRMED, NOT_CONFIRMED or UNKNOWN (the default). |
Each call appends an event (sending the very same event again is ignored); nothing is overwritten, and several actions on one decision are normal (HELD, then ESCALATED, then REFUNDED). Every event may carry an owner: an opaque identifier of the person or system that acted, up to 64 characters of A-Z a-z 0-9 . _ : -. Never send a name or an email address; 422 invalid_owner refuses anything else.
Exposure is not prevented loss
A HIGH_RISK answer means a material risk signal was present. It does not mean a loss was avoided, and ChainZap never counts it as one. Only an outcome you record with loss_prevented: "CONFIRMED" is a prevented loss. Report on outcomes, not on recommendations.
verification_final and risk_final preserve the separate finality axes as of the decision. They are null on historical decisions made before policy b2b-tx-2026-10.3; read those decisions under their original versions.decision policy.
Idempotency
Idempotency-Key ties every attempt to send a request to one logical check. It is an operation key, not an API key.
Persist a key per logical operation
Idempotency-Key accepts 1 to 128 printable ASCII characters. Keys are scoped to your organization and the normalized request body. Store the key and the body before the first attempt and reuse both on every retry, including retries from another server or after API key rotation. Never include credentials or personal information in a key.
| Situation | API response |
|---|---|
| The operation is complete | The original response, byte for byte, with Idempotent-Replayed: true and the original X-Request-ID. |
| The operation is still running | 409 idempotency_in_progress with Retry-After; retryable. |
| Same key, different body | 409 idempotency_conflict; not retryable. Fix the link between the key and the operation. |
Retention and errors
The default retention is 24 hours; confirm any contracted retention change with support. After retention expires, the key can represent a new charged execution. Bound automatic retries to the retention window and keep your own payment-operation ledger.
What is stored and replayed: every 200 answer, including a pending or LIMITED_DATA one, and the 404 and 422 answers given after the check was accepted, for example transaction_not_found, invalid_expected_amount, NETWORK_REQUIRED, NETWORK_AMBIGUOUS and an address that fails validation for the network discovery resolved. retryable=true describes the failure; it does not erase a stored response, so 404 transaction_not_found replays for the whole retention period under the same key.
What is never stored: 429 and every 5xx. Retrying with the same key runs the check again, which is exactly what those errors ask for. Refusals made before a check is accepted are not stored either: authentication, 403, 413, request-schema 422 and contract 422 such as expected_fields_required.
Stop automatic retrying when Idempotent-Replayed: true accompanies a stored answer. Once you have received and reconciled it, create a new logical check with a new key if your workflow needs a later observation, for example of a pending or not-yet-indexed transaction after Retry-After. Never use a new key merely because the original network outcome is unknown.
Endpoint and network are part of the operation
Both check endpoints share your organization's key namespace. Reusing a key on another endpoint or with a changed body returns 409 idempotency_conflict, even if the hash is unchanged. A resolved network and the original result are retained on replay; the API checks that access to that network is still allowed.
For NETWORK_REQUIRED or NETWORK_AMBIGUOUS, first reconcile the received error, then supply network in a new operation with a new key. A replay does not run network discovery again.
Rate limits, quota and concurrency
Organization limits
Limits come from your current versioned plan or from a custom entitlement assignment. Inspect /v1/usage and the Plan and billing page in the developer dashboard. Published beta prices and included checks are in plans and payment; request-rate and concurrency limits are preliminary until general availability.
| Response headers | Meaning |
|---|---|
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset |
Your organization's request capacity, what is left of it and when it resets. |
X-Quota-Limit, X-Quota-Remaining, X-Quota-Reset |
The included checks of the current billing period, what is left of them and when the period ends. X-Quota-Available adds extra checks. |
Reset headers use Unix seconds. A paid billing period is anchored to the confirmed payment; an organization without a paid plan keeps a UTC calendar month. Periods follow UTC regardless of your browser's timezone. All API keys and requests made in the developer dashboard share the same quota. When a check draws on included checks, X-Quota-Remaining already counts it: its quota is reserved while it runs and returned if the answer is not charged, so a free answer shows one less than /v1/usage reports afterwards. An idempotent replay does not touch quota and carries no X-Quota-* headers.
Backpressure
Rate exhaustion returns 429 rate_limit_exceeded. Too many in-flight checks returns 429 concurrency_limit_exceeded. A full quota returns 429 quota_exceeded. Honor Retry-After, which may be long for a monthly quota. Replays still pass through access, rate and concurrency controls, but do not charge again.
Checks that reach the data sources and return no complete, final result (pending, not found, partial) are never charged, and a day of them is capped per organization (500 by default). Poll a pending transaction with backoff rather than in a tight loop. Past that ceiling the API answers 429 rate_limit_exceeded until the ceiling resets at the end of the UTC day; each answer's Retry-After is at most an hour. A healthy integration never reaches it.
Use a bounded request queue and per-organization concurrency on your server. Plan changes affect future entitlements and do not rewrite historical usage.
Batches
A batch file holds up to 200 rows and 256 KiB; an organization runs at most two batches at a time (checked when a batch starts). A running batch uses at most half of your organization's request rate, so your own checks keep their share, and it pauses rather than fails when the quota or the daily ceiling of unbilled checks runs out. Each distinct transaction in a batch is charged once.
Spend protection
Every organization has a cap on what ChainZap spends on paid data sources for its checks per UTC day; support can raise or lower it. Past the cap a check still answers, from cached data where it exists. A risk screen that would need a new paid call is skipped: on a transaction check the AML source in source_coverage.risk_sources reports error_code: "spend_cap" ("daily_cap" when the AML source's service-wide daily ceiling is reached instead), risk_status is INSUFFICIENT, and the answer is not charged; a wallet check lists aml_provider_unavailable. The cap resets at 00:00 UTC; a new check before then usually returns the same gap, whatever risk_retry_after_seconds suggests. spend_cap is also reported while spend cannot be accounted (an unknown tariff or an unavailable counter); that gap clears when accounting recovers, not at 00:00 UTC. Payment verification is not affected: a final match stays final.
Before each uncached paid attempt, ChainZap atomically reserves its full configured cost, including in-flight calls. A call that would exceed the remaining cap is skipped. Unknown tariffs or unavailable accounting block new paid calls when a cap is configured. Definitely unsent requests return their reservation; a lost response conservatively keeps it. Cached evidence remains usable. This limit affects risk coverage, not final payment verification.
Ledger reads
Reading obligations, decisions and batches (a lookup, a status poll, a page of rows, an export) does not spend the request rate of your checks: reads have their own bucket per organization, four times your per-minute rate and at least 120 a minute, so following a batch never takes capacity from your checks. Past it a read answers 429 rate_limit_exceeded with Retry-After; on a read, the X-RateLimit-* headers describe this bucket.
Automatic network discovery
POST /v1/check and POST /v1/transaction/check share the same organization limits. A request without network reserves quota before looking up transaction facts across the available networks. Discovery is bounded and does not run a risk check for every network. Only the completed check with complete coverage is charged; a discovery error releases the reservation.
Retries and timeouts
Client deadline
Use a client deadline longer than the 12-second server hard deadline, for example 15 seconds per attempt. A wallet check has a 30-second server budget; use about 35 seconds for it. The latency target is p95 at most 5 seconds; it is a release gate, not an unconditional guarantee. Network time is outside the server budget.
Bounded retries
For a received error, retry only when error.retryable=true. Honor Retry-After, use exponential backoff with jitter, limit the number of attempts and cap the overall workflow duration. If the instructed wait exceeds your interactive budget, schedule a retry rather than shorten the wait.
Lost connection
For a network exception, retry the same stored body and Idempotency-Key. Preserve both across restarts. Stop on an idempotent replay of a stored error and reconcile the result. 409 idempotency_conflict requires an integration fix; 409 idempotency_in_progress, 429, 503 and 504 may be retried under these rules.
Record only the request ID and the public error code in ordinary logs. Do not log request bodies, API keys, wallet values or provider payloads. The executable examples follow these rules.
A new observation
A pending transaction can later finalize, but replaying its stored response does not fetch a newer state. Once the current result is received and reconciled, schedule a new logical check with a new key if you need a later observation. For an unresolved network error, follow network discovery; NETWORK_REQUIRED and NETWORK_AMBIGUOUS require explicit network context, not automatic retries.
Verification and risk finality
verification_final describes the payment facts and comparison. result_final is its alias; retryable is its opposite, and retry_after_seconds is the suggested wait for another verification observation. A final chain transaction with an exact expected match returns verification_final: true and integrity_status: MATCH even when KYT is unavailable and risk_status: INSUFFICIENT.
risk_final is true once checking again is not expected to fill a gap in the risk assessment: the transaction is final, its sources agree, and no AML, sanctions or token check had a temporary gap (an outage or a stale list). While the transaction is pending or not found, risk_final is false whatever risk_status says, and risk_retry_after_seconds equals retry_after_seconds: risk is assessed again once the transaction is final. risk_retryable is its opposite; risk_retry_after_seconds suggests when to check risk again. A permanent coverage limit can be final while remaining INSUFFICIENT: finality does not mean clearance. KYT describes risk at check time and can change later even after a final assessment.
Pending transactions return integrity_status: NOT_EVALUATED, verification_final: false, null match flags, NOT_EVALUATED for every requested comparison and no EXPECTED_*_MISMATCH reason: terms that differ are reported only once the transaction is final. When the sources disagree about the transaction itself (transaction_status: INSUFFICIENT, coverage_status: DISAGREEMENT), the answer is not final either, but it still compares the transfers the sources report and can carry EXPECTED_*_MISMATCH: act on verification_final: false and check again. Observed transfers remain evidence, not a final payment match. Verification retries wait 5–120 seconds for pending finality, 15 seconds for an absent transaction, or 30 seconds for a temporary chain-source gap. A temporary KYT gap suggests a separate risk retry after 30 seconds. When the AML source reports error_code spend_cap (your organization's daily cap on paid sources is reached, or spend cannot be accounted for the moment) or daily_cap (the AML source's service-wide daily ceiling is reached), a reached cap resets at 00:00 UTC, and a new check before then usually returns the same gap; see limits. On a transaction that is not found, risk_retryable is true although risk_status is NOT_EVALUATED: risk is assessed once the transaction appears.
Missing KYT does not reopen final verification and never permits PROCEED: MATCH with risk_status: INSUFFICIENT recommends MANUAL_REVIEW. Only final answers with complete coverage are charged; a final verification with partial KYT coverage remains free. For a new observation, use a new Idempotency-Key; replaying the same key returns the stored answer under its original policy.
Error reference
Public envelope
{"request_id":"merchant-order-1001-attempt-1","error":{"code":"provider_unavailable","message":"Transaction data is temporarily unavailable","retryable":true}}
The response header X-Request-ID identifies the same response. Branch on the stable code and retryable; do not parse the human-readable message. Gateway failures may not have this envelope: treat an invalid or missing envelope as an unresolved transport outcome and preserve the original idempotency key.
| HTTP | Codes | Action |
|---|---|---|
| 401 | invalid_api_key |
Correct the server credentials; do not retry blindly. |
| 403 | tenant_suspended, network_not_enabled, check_kind_not_enabled |
Resolve access with your organization; the pilot contract covers TRON transaction checks only. |
| 403 | forbidden |
The request did not come through Cloudflare: it was sent straight to a server address. Call https://api.chainzap.io. This edge answer carries its request_id in the body only. When api.chainzap.io itself is pinned to a server address, the server refuses the request with a plain 403 page and no JSON. |
| 403 | network_disabled |
Adapter activation is pending; contact support. |
| 403 | ledger_not_enabled, batch_not_enabled |
The obligation ledger or batches are not switched on; send the check without ledger fields. |
| 404 | obligation_not_found, decision_not_found, payment_event_not_found, allocation_not_found, batch_not_found |
The record does not exist in this environment. A payment event exists only after a check that named an obligation recorded it with complete coverage. |
| 404 | transaction_not_found |
/v1/check only. Every checked network confirmed the transaction is absent. Check the hash and indexing time; bound retries. |
| 409 | idempotency_conflict |
Fix the link between the key and the body (or, for a batch upload, the file); not retryable. |
| 409 | idempotency_in_progress |
Wait for Retry-After and retry the same operation. |
| 409 | instruction_conflict, instruction_version_required |
The obligation's instruction is recorded with other terms. Send a new instruction_version for changed terms; recorded versions never change. |
| 409 | allocation_exceeds_event, payment_event_not_settled, allocation_token_mismatch |
The shares exceed the payment event, the event did not execute or is not final, or it is in another token than the obligation. |
| 409 | attempt_conflict |
The attempt is recorded with another channel, provider reference, amount or transaction, by POST /v1/obligations/attempts or by a check that names its attempt_reference with another tx_hash; record a retry or a provider switch as a new attempt_reference. |
| 409 | batch_not_executable, insufficient_quota, nothing_to_retry |
The batch is not in a state for this action, the quota cannot cover it (send allow_partial), or no row can be retried. |
| 413 | payload_too_large |
The body exceeds 4 KiB (256 KiB for a batch upload); send only the documented fields. |
| 413 | batch_too_large |
The batch file has more than 200 rows; split it. |
| 415 | unsupported_media_type |
Send the body as Content-Type: application/json, or text/csv for a batch upload. |
| 422 | malformed_tx_hash, invalid_address, invalid_network, invalid_tron_address, invalid_eth_address, invalid_ton_address, invalid_expected_amount, invalid_idempotency_key, invalid_query_parameter, validation_error |
Correct the invalid request. |
| 422 | invalid_amount_tolerance, invalid_reference, invalid_owner, instruction_terms_required |
Correct the request: a tolerance finer than the token's decimals, a reference outside 1 to 128 printable ASCII characters, an owner that is not an opaque identifier, or an obligation without any payment terms. |
| 422 | invalid_csv, invalid_csv_header, confirmation_required |
Fix the batch file, or confirm the estimate with confirm: true. |
| 422 | expected_fields_required, token_not_enabled |
Your organization's contract requires all three expected_* fields and the token it covers. Fix the request; not retryable. |
| 422 | NETWORK_REQUIRED, NETWORK_AMBIGUOUS |
Insufficient input, not success: the checked networks left the answer open. Specify the network and use a new key. See network discovery. |
| 429 | rate_limit_exceeded, quota_exceeded, concurrency_limit_exceeded |
Honor Retry-After; reduce concurrency or wait for the quota reset. |
| 429 | batch_limit_reached |
Two batches are already running for your organization; wait for one to finish. |
| 503 | provider_unavailable, rate_limiter_unavailable, api_disabled, api_not_configured |
Retry only when retryable and within your retry budget; keep the same key. |
| 504 | request_timeout |
Retry the same key and body after the instructed delay. It also answers when another request held the same payment or obligation in the ledger at that moment: nothing was stored or charged. |
| 500 | internal_error |
Use the bounded retry policy and contact support with X-Request-ID. |
Check Idempotent-Replayed: a stored error does not refresh itself on replay. See idempotency. Never assume that an HTTP error means no request was accepted.
Security recommendations
Protect credentials
Call the API from your backend. Store API keys in a secret manager, limit access to the integration service and rotate a key after suspected exposure. Never paste a key into a support ticket, URL, issue tracker, analytics event, browser console or frontend bundle.
Keep your identity provider protected with its available strong authentication policies. Accept invitations only from a trusted organization administrator. Sign out on shared devices; use Organization settings in the developer dashboard to sign out everywhere.
Handle data deliberately
Validate incoming payment requests on your server. Bind checks to your own payment-operation IDs and reconcile ambiguous outcomes. Use exact token contracts and decimal strings, and handle null and unknown states explicitly. Escape organization names, key labels and response values before displaying them in your own UI.
Retain only the data your workflow needs. Restrict access to response details. Send support the response X-Request-ID and the public error code; omit keys, balances and raw payloads.
API reference
Download OpenAPI. Field names and types below come directly from the public API contract. A required field may still accept null when the type allows it. Read the guides above for each field’s meaning.
POST /v1/transaction/check
Check one transaction. Send X-API-Key and a stored Idempotency-Key. Whether network is required depends on the endpoint.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
| 500 | Internal error. Keep the X-Request-ID for support. |
POST /v1/check
Check one transaction. Send X-API-Key and a stored Idempotency-Key. Whether network is required depends on the endpoint.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/usage
Read your organization’s limits and usage. The optional days parameter accepts 1-90 and defaults to 30.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 422 | Correct the request fields. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/catalog
Read the published beta pricing catalog: plans, included checks and extra-check terms.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
POST /v1/wallet/check
Check one wallet address. Send X-API-Key and a stored Idempotency-Key. The network is optional and is read from the address format.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
| 500 | Internal error. Keep the X-Request-ID for support. |
POST /v1/obligations
Record an obligation and its instruction. A changed recipient, amount, token or network is a new instruction_version.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
POST /v1/obligations/lookup
Read an obligation back with its instruction history, attempts, allocations and decisions. The reference travels in the body, never in the URL.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
POST /v1/obligations/attempts
Record one execution attempt of an obligation, or a new status of it. A retry or a provider switch is a new attempt_reference.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
POST /v1/allocations
Declare how one payment event settles one or more obligations, for example an aggregate payout.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
POST /v1/allocations/{allocation_id}/reversal
Reverse an allocation. It stays on record with the time and reason.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
GET /v1/decisions/{decision_id}
Read ChainZap's decision as it was made, with its evidence and what you recorded after it.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
POST /v1/decisions/{decision_id}/actions
Record what you did with a decision, how you resolved it, or how it turned out. Recorded next to the decision, never into it.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
POST /v1/decisions/{decision_id}/resolution
Record what you did with a decision, how you resolved it, or how it turned out. Recorded next to the decision, never into it.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
POST /v1/decisions/{decision_id}/outcome
Record what you did with a decision, how you resolved it, or how it turned out. Recorded next to the decision, never into it.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 504 | The request exceeded the server time limit. |
POST /v1/batches
Upload a CSV of up to 200 payments. Every row is validated, compared with the others and with earlier checks, and the cost is estimated before anything runs.
| HTTP | Response |
|---|---|
| 201 | Created: the batch was accepted and checked before it runs; start it with execute. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
GET /v1/batches
Upload a CSV of up to 200 payments. Every row is validated, compared with the others and with earlier checks, and the cost is estimated before anything runs.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
GET /v1/batches/{batch_id}
Read a batch's status, progress, preflight, estimate and summary, or its rows with their results.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
GET /v1/batches/{batch_id}/rows
Read a batch's status, progress, preflight, estimate and summary, or its rows with their results.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
GET /v1/batches/{batch_id}/export.csv
Export a batch as CSV for spreadsheets
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
POST /v1/batches/{batch_id}/execute
Start a preflighted batch after confirming its estimate, retry only rows whose answer can still change, or cancel it.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
POST /v1/batches/{batch_id}/retry
Start a preflighted batch after confirming its estimate, retry only rows whose answer can still change, or cancel it.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
POST /v1/batches/{batch_id}/cancel
Start a preflighted batch after confirming its estimate, retry only rows whose answer can still change, or cancel it.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
POST /v1/escrow-deals
Create an escrow deal draft, list the organization's deals, or find one by your reference.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals
Create an escrow deal draft, list the organization's deals, or find one by your reference.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/lookup
Create an escrow deal draft, list the organization's deals, or find one by your reference.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/events
Read the event feed after a sequence number, or send one event to the webhook again.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/events/{event_id}/redeliver
Read the event feed after a sequence number, or send one event to the webhook again.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/webhook
Set, read or disable the signed webhook, rotate its secret, or send a test event.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
PUT /v1/escrow-deals/webhook
Set, read or disable the signed webhook, rotate its secret, or send a test event.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
DELETE /v1/escrow-deals/webhook
Set, read or disable the signed webhook, rotate its secret, or send a test event.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/webhook/rotate-secret
Set, read or disable the signed webhook, rotate its secret, or send a test event.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/webhook/test
Set, read or disable the signed webhook, rotate its secret, or send a test event.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/resolvers
Register your external resolvers, list them, read their accounts on-chain again, or disable them. A resolver is optional, and ChainZap is never one.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/resolvers
Register your external resolvers, list them, read their accounts on-chain again, or disable them. A resolver is optional, and ChainZap is never one.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/resolvers/{resolver_id}
Register your external resolvers, list them, read their accounts on-chain again, or disable them. A resolver is optional, and ChainZap is never one.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/resolvers/{resolver_id}/verify
Register your external resolvers, list them, read their accounts on-chain again, or disable them. A resolver is optional, and ChainZap is never one.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/resolvers/{resolver_id}/disable
Register your external resolvers, list them, read their accounts on-chain again, or disable them. A resolver is optional, and ChainZap is never one.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/resolvers/{resolver_id}/enable
Register your external resolvers, list them, read their accounts on-chain again, or disable them. A resolver is optional, and ChainZap is never one.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/{ref}
Read one escrow deal, replace the terms of a draft, or cancel a draft.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/{ref}/versions
Read one escrow deal, replace the terms of a draft, or cancel a draft.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/{ref}/cancel
Read one escrow deal, replace the terms of a draft, or cancel a draft.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/{ref}/consent
Read the exact text each party signs, or relay a party's signature.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/{ref}/consents
Read the exact text each party signs, or relay a party's signature.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/{ref}/actions
List the contract calls a party can sign now, or report a transaction you relayed.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/{ref}/transactions
List the contract calls a party can sign now, or report a transaction you relayed.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/{ref}/evidence
Add or read evidence, or read the dispute with both sides' evidence and deadlines.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
POST /v1/escrow-deals/{ref}/evidence
Add or read evidence, or read the dispute with both sides' evidence and deadlines.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
PUT /v1/escrow-deals/{ref}/evidence/files
Add or read evidence, or read the dispute with both sides' evidence and deadlines.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/{ref}/evidence/{evidence_id}/content
Add or read evidence, or read the dispute with both sides' evidence and deadlines.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
GET /v1/escrow-deals/{ref}/dispute
Add or read evidence, or read the dispute with both sides' evidence and deadlines.
| HTTP | Response |
|---|---|
| 200 | Success: the body follows this endpoint's schema. For a check, read the status axes and coverage. |
| 401 | API key is invalid or has been revoked. |
| 403 | Your organization or network does not have access. |
| 404 | Not found in your organization and environment. On /v1/check: the transaction was not found in the selected network or, without a network, in any network checked. |
| 409 | Conflict: the request is still running, its idempotency key was reused with a different body, or it conflicts with recorded state. Read error.code. |
| 413 | The request body is larger than this endpoint accepts. |
| 415 | This content type is not accepted here: JSON, or CSV for a batch upload. |
| 422 | Correct the request fields. |
| 429 | A rate, concurrency, monthly quota, daily unbilled-checks or active-batch limit was reached. Read error.code and Retry-After. |
| 500 | Internal error. Keep the X-Request-ID for support. |
| 503 | API access or a required service is unavailable. |
| 504 | The request exceeded the server time limit. |
ActionRequest
| Field | Type / values | Required |
|---|---|---|
owner |
string / null |
No |
action |
"CREDITED", "PAID", "HELD", "REJECTED", "REFUNDED", "ESCALATED", "RETRIED", "NO_ACTION", "OTHER" |
Yes |
action_at |
string / null |
No |
ActionView
| Field | Type / values | Required |
|---|---|---|
action |
string |
Yes |
contract |
string |
Yes |
function |
string |
Yes |
parameters |
string |
Yes |
data |
string |
Yes |
fee_limit_sun |
integer |
Yes |
call_value |
integer |
No |
estimated_energy |
integer / null |
Yes |
estimated_trx |
string / null |
Yes |
note |
string / null |
No |
ActionsResponse
| Field | Type / values | Required |
|---|---|---|
role |
"BUYER", "SELLER" |
Yes |
address |
string |
Yes |
state |
string / null |
Yes |
status |
string |
Yes |
actions |
ActionView[] |
Yes |
AllocationRequest
| Field | Type / values | Required |
|---|---|---|
network |
"tron", "eth", "ton" |
Yes |
tx_hash |
string |
Yes |
event_ref |
string |
Yes |
allocations |
AllocationShare[] |
Yes |
owner |
string / null |
No |
AllocationResponse
| Field | Type / values | Required |
|---|---|---|
allocation_id |
string |
Yes |
external_reference |
string / null |
Yes |
event |
EventResponse |
Yes |
allocated_amount |
string |
Yes |
status |
string |
Yes |
source |
string |
Yes |
instruction_version |
integer / null |
Yes |
decision_id |
string / null |
Yes |
created_at |
string |
Yes |
reversed_at |
string / null |
Yes |
reversal_reason |
string / null |
Yes |
AllocationResultResponse
| Field | Type / values | Required |
|---|---|---|
allocations |
AllocationResponse[] |
Yes |
obligations |
ObligationResponse[] |
Yes |
AllocationShare
| Field | Type / values | Required |
|---|---|---|
external_reference |
string |
Yes |
amount |
string |
Yes |
AmountComparisonResponse
| Field | Type / values | Required |
|---|---|---|
expected |
string / null |
Yes |
actual |
string / null |
Yes |
result |
"EXACT", "WITHIN_TOLERANCE", "UNDERPAID", "OVERPAID", "NOT_EVALUATED", "INSUFFICIENT" |
Yes |
tolerance |
string / null |
Yes |
delta |
string / null |
Yes |
delta_raw |
string / null |
Yes |
AmountView
| Field | Type / values | Required |
|---|---|---|
value |
string |
Yes |
minor |
string |
Yes |
token |
string |
Yes |
symbol |
string |
No |
decimals |
integer |
Yes |
AttemptRequest
| Field | Type / values | Required |
|---|---|---|
external_reference |
string |
Yes |
attempt_reference |
string |
Yes |
status |
"CREATED", "SUBMITTED", "BROADCAST", "TIMEOUT", "FAILED", "CANCELLED", "PROVIDER_CONFIRMED", "UNKNOWN" |
No |
channel |
string / null |
No |
provider_reference |
string / null |
No |
amount |
string / null |
No |
network |
"tron", "eth", "ton" / null |
No |
tx_hash |
string / null |
No |
instruction_version |
integer / null |
No |
attempt_created_at |
string / null |
No |
AttemptResponse
| Field | Type / values | Required |
|---|---|---|
attempt_reference |
string / null |
Yes |
status |
"CREATED", "SUBMITTED", "BROADCAST", "TIMEOUT", "FAILED", "CANCELLED", "PROVIDER_CONFIRMED", "UNKNOWN" |
Yes |
channel |
string / null |
Yes |
provider_reference |
string / null |
Yes |
amount |
string / null |
Yes |
network |
string / null |
Yes |
tx_hash |
string / null |
Yes |
instruction_version |
integer / null |
Yes |
attempt_created_at |
string |
Yes |
updated_at |
string |
Yes |
status_history |
object[] |
Yes |
execution_confirmed |
boolean |
Yes |
redacted |
boolean |
Yes |
BalancesView
| Field | Type / values | Required |
|---|---|---|
accrued |
PartyMoney |
Yes |
claimable |
PartyMoney |
Yes |
withdrawn |
PartyMoney |
Yes |
held_by_contract |
Money |
Yes |
BatchListResponse
| Field | Type / values | Required |
|---|---|---|
batches |
BatchResponse[] |
Yes |
BatchResponse
| Field | Type / values | Required |
|---|---|---|
batch_id |
string |
Yes |
environment |
"live", "sandbox" |
Yes |
status |
"PREFLIGHTED", "QUEUED", "RUNNING", "PAUSED", "CANCELLING", "COMPLETED", "CANCELLED", "FAILED" |
Yes |
pause_reason |
string / null |
Yes |
row_count |
integer |
Yes |
progress |
object |
Yes |
defaults |
object |
Yes |
preflight |
object |
Yes |
estimate |
object |
Yes |
summary |
object / null |
Yes |
created_at |
string |
Yes |
started_at |
string / null |
Yes |
completed_at |
string / null |
Yes |
BatchRowResponse
| Field | Type / values | Required |
|---|---|---|
row_no |
integer |
Yes |
kind |
"check", "obligation" |
Yes |
state |
"PENDING", "CLAIMED", "DONE", "FAILED", "RETRYABLE", "SKIPPED_DUPLICATE", "SKIPPED_INVALID", "CANCELLED" |
Yes |
attempt |
integer |
Yes |
external_reference |
string / null |
Yes |
network |
string / null |
Yes |
tx_hash |
string / null |
Yes |
errors |
string[] |
Yes |
warnings |
string[] |
Yes |
duplicate_of |
integer / null |
Yes |
error_code |
string / null |
Yes |
result |
object / null |
Yes |
redacted |
boolean |
Yes |
BatchRowsResponse
| Field | Type / values | Required |
|---|---|---|
batch_id |
string |
Yes |
rows |
BatchRowResponse[] |
Yes |
next_after |
integer / null |
Yes |
CatalogItemResponse
| Field | Type / values | Required |
|---|---|---|
plan_code |
string |
Yes |
plan_version |
integer |
Yes |
name |
string |
Yes |
environment |
"live", "sandbox" |
Yes |
commercial_status |
"published", "custom" |
Yes |
currency |
string |
Yes |
monthly_price_minor |
integer / null |
Yes |
included_checks |
integer / null |
Yes |
overage_unit_price_minor |
integer / null |
Yes |
package |
CatalogPackageTerms / null |
Yes |
CatalogPackageTerms
| Field | Type / values | Required |
|---|---|---|
min_quantity |
integer |
Yes |
max_quantity |
integer |
Yes |
step |
integer |
Yes |
expires_days |
integer / null |
Yes |
CatalogResponse
| Field | Type / values | Required |
|---|---|---|
pricing_policy |
string |
Yes |
revision |
integer |
Yes |
currency |
string |
Yes |
consumption_unit |
"transaction_check" |
No |
renewal |
"manual" |
No |
items |
CatalogItemResponse[] |
Yes |
computed_at |
string |
Yes |
Category
| Field | Type / values | Required |
|---|
CheckDetails
| Field | Type / values | Required |
|---|---|---|
request_id |
string |
Yes |
tx_hash |
string |
Yes |
network |
"tron", "eth", "ton" |
Yes |
transaction_type |
string |
Yes |
transaction_category |
"eth_transfer", "erc20_transfer", "ton_transfer", "jetton_transfer", "trx_transfer", "trc10_transfer", "trc20_transfer", "smart_contract_call", "smart_contract_deploy", "staking", "voting", "governance", "resource_operation", "account_operation", "exchange", "market", "permission_update", "other", "unknown" |
Yes |
transaction_state |
"confirmed", "pending", "failed", "not_found", "unknown" |
Yes |
confirmations |
integer / null |
Yes |
required_confirmations |
integer |
Yes |
sender |
string / null |
Yes |
recipient |
string / null |
Yes |
token_contract |
string / null |
Yes |
token_symbol |
string / null |
Yes |
decimals |
integer / null |
Yes |
amount |
string / null |
Yes |
transfers |
DetailedTransferResponse[] |
Yes |
transfers_truncated |
boolean |
Yes |
aml_risk_level |
"low", "moderate", "high", "severe", "unknown" |
Yes |
schema_version |
"0.3" |
Yes |
policy_version |
string |
Yes |
sanctions_hit |
boolean / null |
Yes |
direct_sanctions_match |
boolean / null |
Yes |
indirect_sanctions_exposure |
boolean / null |
Yes |
risk_exposure |
boolean / null |
Yes |
key_exposure |
ExposureResponse[] |
Yes |
token_authenticity |
"official", "fake", "unknown" |
Yes |
recipient_match |
boolean / null |
Yes |
token_match |
boolean / null |
Yes |
amount_match |
boolean / null |
Yes |
coverage |
"complete", "partial" |
Yes |
workflow_coverage |
"complete", "partial" |
Yes |
source_coverage |
SourceCoverageResponse |
Yes |
freshness |
FreshnessResponse |
Yes |
overall_state |
"CLEAR", "REVIEW", "HIGH_RISK", "LIMITED_DATA" |
Yes |
environment |
"live", "sandbox" |
No |
reasons |
ReasonResponse[] |
Yes |
decision_id |
string / null |
Yes |
direction |
"INCOMING", "OUTGOING" / null |
Yes |
workflow_type |
"PAYOUT", "DEPOSIT", "INVOICE", "REFUND", "SETTLEMENT", "OTHER" / null |
Yes |
versions |
VersionsResponse |
Yes |
transaction_status |
"CONFIRMED", "PENDING", "FAILED", "NOT_FOUND", "INSUFFICIENT" |
Yes |
integrity_status |
"MATCH", "MISMATCH", "AMBIGUOUS", "NOT_EVALUATED", "INSUFFICIENT" |
Yes |
risk_status |
"HIGH_RISK", "REVIEW", "NO_MATERIAL_SIGNAL", "NOT_EVALUATED", "INSUFFICIENT" |
Yes |
coverage_status |
"OK", "DEGRADED", "UNAVAILABLE", "DISAGREEMENT", "SKIPPED" |
Yes |
status_drivers |
StatusDriversResponse |
Yes |
result_final |
boolean |
Yes |
verification_final |
boolean |
Yes |
risk_final |
boolean |
Yes |
risk_retryable |
boolean |
Yes |
risk_retry_after_seconds |
integer / null |
Yes |
retryable |
boolean |
Yes |
retry_after_seconds |
integer / null |
Yes |
recommended_action |
"PROCEED", "CONFIRM_INTERNAL_STATE", "MANUAL_REVIEW", "RECHECK_LATER", "NOT_EXECUTED", "HOLD_AND_ESCALATE" |
Yes |
integrity |
IntegrityResponse |
Yes |
risk |
RiskSummaryResponse |
Yes |
evidence_items |
EvidenceItemResponse[] |
Yes |
coverage_limitations |
CoverageLimitationsResponse |
Yes |
obligation |
ObligationSummaryResponse / null |
No |
reuse |
ReuseResponse / null |
No |
selected_transfer_index |
integer / null |
Yes |
finalized |
boolean |
Yes |
finality_policy |
string |
Yes |
trace_complete |
boolean / null |
Yes |
evidence |
object |
Yes |
limitations |
string[] |
Yes |
checked_networks |
"tron", "eth", "ton"[] |
Yes |
ConsentPackage
| Field | Type / values | Required |
|---|---|---|
version |
integer |
Yes |
deal_id |
string |
Yes |
message |
string |
Yes |
params |
object |
Yes |
terms |
object |
Yes |
terms_canonical |
string |
Yes |
terms_hash |
string |
Yes |
agreement_expires_at |
string |
Yes |
factory |
string |
Yes |
ConsentRequest
| Field | Type / values | Required |
|---|---|---|
version |
integer |
Yes |
role |
"BUYER", "SELLER" |
Yes |
signature |
string |
Yes |
ConsentStatus
| Field | Type / values | Required |
|---|---|---|
signed |
boolean |
Yes |
method |
"SIGNATURE", "ONCHAIN_APPROVAL" / null |
Yes |
at |
string / null |
Yes |
ConsentsView
| Field | Type / values | Required |
|---|---|---|
buyer |
ConsentStatus |
Yes |
seller |
ConsentStatus |
Yes |
ContractView
| Field | Type / values | Required |
|---|---|---|
factory |
string |
Yes |
escrow |
string / null |
Yes |
deal_id |
string / null |
Yes |
ruling_hash |
string / null |
Yes |
observed_at |
string / null |
Yes |
out_of_sync |
boolean |
Yes |
CoverageLimitationsResponse
| Field | Type / values | Required |
|---|---|---|
runtime |
ReasonCode[] |
Yes |
product |
ReasonCode[] |
Yes |
CreateDealRequest
| Field | Type / values | Required |
|---|---|---|
buyer |
string |
Yes |
seller |
string |
Yes |
amount |
string |
Yes |
category |
Category |
Yes |
title |
string |
Yes |
description |
string |
No |
delivery |
DeliveryInput |
Yes |
timeline |
TimelineInput |
Yes |
resolver_enabled |
boolean |
No |
resolver_id |
string / null |
No |
resolver_fee |
string / null |
No |
external_reference |
string |
Yes |
obligation_reference |
string / null |
No |
CustomerContext
| Field | Type / values | Required |
|---|---|---|
credit_status |
"NOT_CREDITED", "CREDITED", "PARTIALLY_CREDITED", "UNKNOWN" / null |
No |
allocation_status |
"NOT_ALLOCATED", "PARTIALLY_ALLOCATED", "ALLOCATED", "UNKNOWN" / null |
No |
DealListResponse
| Field | Type / values | Required |
|---|---|---|
deals |
DealResponse[] |
Yes |
next_before |
string / null |
Yes |
DealResponse
| Field | Type / values | Required |
|---|---|---|
id |
string |
Yes |
external_reference |
string |
Yes |
obligation_reference |
string / null |
Yes |
environment |
"live", "sandbox" |
Yes |
network |
string |
Yes |
status |
string |
Yes |
protocol_version |
1, 2 |
Yes |
state |
string / null |
Yes |
settlement_reason |
string / null |
Yes |
category |
string |
Yes |
title |
string / null |
Yes |
pricing_class |
string |
Yes |
parties |
Parties |
Yes |
resolver_enabled |
boolean |
Yes |
resolver |
ResolverView / null |
Yes |
amount |
AmountView |
Yes |
fee |
FeeView |
Yes |
terms |
TermsView |
Yes |
timeline |
TimelineView |
Yes |
settlement |
SettlementView / null |
Yes |
funding |
FundingView / null |
Yes |
contract |
ContractView |
Yes |
balances |
BalancesView |
Yes |
links |
Links |
Yes |
created_at |
string / null |
Yes |
updated_at |
string / null |
Yes |
transactions |
TransactionView[] |
No |
replayed |
boolean |
No |
DecisionEventResponse
| Field | Type / values | Required |
|---|---|---|
kind |
"ACTION", "RESOLUTION", "OUTCOME" |
Yes |
action |
string / null |
Yes |
resolution |
string / null |
Yes |
outcome_status |
string / null |
Yes |
loss_prevented |
string / null |
Yes |
owner |
string / null |
Yes |
occurred_at |
string |
Yes |
recorded_at |
string |
Yes |
DecisionResponse
| Field | Type / values | Required |
|---|---|---|
decision_id |
string |
Yes |
decided_at |
string |
Yes |
channel |
string |
Yes |
transaction_status |
string |
Yes |
integrity_status |
string |
Yes |
risk_status |
string |
Yes |
coverage_status |
string |
Yes |
overall_state |
string |
Yes |
recommended_action |
string |
Yes |
reuse_status |
string / null |
Yes |
environment |
"live", "sandbox" |
Yes |
network |
string |
Yes |
external_reference |
string / null |
Yes |
instruction_version |
integer / null |
Yes |
selected_event_ref |
string / null |
Yes |
result_final |
boolean |
Yes |
verification_final |
boolean / null |
Yes |
risk_final |
boolean / null |
Yes |
retryable |
boolean |
Yes |
status_drivers |
object |
Yes |
reason_codes |
string[] |
Yes |
versions |
object |
Yes |
evidence_items |
object[] / null |
Yes |
events |
DecisionEventResponse[] |
Yes |
DecisionSummaryResponse
| Field | Type / values | Required |
|---|---|---|
decision_id |
string |
Yes |
decided_at |
string |
Yes |
channel |
string |
Yes |
transaction_status |
string |
Yes |
integrity_status |
string |
Yes |
risk_status |
string |
Yes |
coverage_status |
string |
Yes |
overall_state |
string |
Yes |
recommended_action |
string |
Yes |
reuse_status |
string / null |
Yes |
DeliveryInput
| Field | Type / values | Required |
|---|---|---|
criteria |
string[] |
Yes |
method |
string |
Yes |
evidence_required |
string[] |
No |
DetailedTransferResponse
| Field | Type / values | Required |
|---|---|---|
index |
integer |
Yes |
asset_type |
string |
Yes |
sender |
string / null |
Yes |
recipient |
string / null |
Yes |
token_contract |
string / null |
Yes |
token_id |
string / null |
Yes |
token_symbol |
string / null |
Yes |
decimals |
integer / null |
Yes |
amount |
string / null |
Yes |
event_ref |
string / null |
No |
execution_status |
"success", "failed", "unknown" |
No |
raw_amount |
string / null |
Yes |
DisputeResponse
| Field | Type / values | Required |
|---|---|---|
state |
string / null |
Yes |
disputed_at |
string / null |
Yes |
resolve_deadline |
string / null |
Yes |
resolver_enabled |
boolean |
Yes |
deadlocked |
boolean |
Yes |
buyer_proposal |
Money / null |
Yes |
seller_proposal |
Money / null |
Yes |
criteria |
string[] |
Yes |
evidence |
EvidenceView[] |
Yes |
ruling |
RulingView / null |
Yes |
ErrorDetail
| Field | Type / values | Required |
|---|---|---|
code |
string |
Yes |
message |
string |
Yes |
retryable |
boolean |
Yes |
ErrorResponse
| Field | Type / values | Required |
|---|---|---|
request_id |
string |
Yes |
error |
ErrorDetail |
Yes |
EventFeedResponse
| Field | Type / values | Required |
|---|---|---|
events |
EventView[] |
Yes |
next_after |
integer |
Yes |
EventResponse
| Field | Type / values | Required |
|---|---|---|
network |
string |
Yes |
tx_hash |
string / null |
Yes |
event_ref |
string |
Yes |
asset_type |
string |
Yes |
token_contract |
string / null |
Yes |
sender |
string / null |
Yes |
recipient |
string / null |
Yes |
amount |
string / null |
Yes |
execution_status |
string |
Yes |
finalized |
boolean |
Yes |
block_number |
integer / null |
Yes |
block_time |
string / null |
Yes |
EventView
| Field | Type / values | Required |
|---|---|---|
seq |
integer |
Yes |
event_id |
string |
Yes |
type |
string |
Yes |
occurred_at |
string |
Yes |
deal |
object |
Yes |
data |
object |
Yes |
EvidenceDisagreementResponse
| Field | Type / values | Required |
|---|---|---|
fields |
string[] |
Yes |
EvidenceFreshnessResponse
| Field | Type / values | Required |
|---|---|---|
age_seconds |
integer / null |
Yes |
stale |
boolean |
Yes |
stale_after_seconds |
integer / null |
Yes |
EvidenceItemResponse
| Field | Type / values | Required |
|---|---|---|
evidence_id |
string |
Yes |
kind |
"transaction_facts", "aml_risk", "sanctions_list", "token_authenticity" |
Yes |
source |
string |
Yes |
subject |
EvidenceSubjectResponse |
Yes |
source_reference |
string / null |
Yes |
observed_at |
string / null |
Yes |
effective_at |
string / null |
Yes |
temporal_scope |
"TRANSACTION_TIME", "CHECK_TIME", "LIST_PUBLICATION" |
Yes |
coverage |
"checked", "checked_stale", "checked_freshness_unknown", "not_checked", "not_applicable", "unavailable", "partial", "disagreement" |
Yes |
freshness |
EvidenceFreshnessResponse |
Yes |
dependency |
"required", "optional", "not_applicable" |
Yes |
disagreement |
EvidenceDisagreementResponse / null |
Yes |
evidence_version |
string |
Yes |
EvidenceListResponse
| Field | Type / values | Required |
|---|---|---|
evidence |
EvidenceView[] |
Yes |
EvidenceSubjectResponse
| Field | Type / values | Required |
|---|---|---|
type |
"transaction", "transaction_addresses", "token" |
Yes |
ref |
string / null |
Yes |
EvidenceView
| Field | Type / values | Required |
|---|---|---|
id |
string |
Yes |
author_role |
string |
Yes |
purpose |
string |
Yes |
kind |
string |
Yes |
terms_version |
integer |
Yes |
file_name |
string / null |
Yes |
media_type |
string / null |
Yes |
size_bytes |
integer / null |
Yes |
sha256 |
string / null |
Yes |
note |
string / null |
Yes |
supersedes |
string / null |
Yes |
uploaded |
boolean |
Yes |
content_deleted |
boolean |
Yes |
created_at |
string |
Yes |
ExecuteRequest
| Field | Type / values | Required |
|---|---|---|
confirm |
boolean |
Yes |
allow_partial |
boolean |
No |
ExposureResponse
| Field | Type / values | Required |
|---|---|---|
category |
string |
Yes |
exposure_type |
string |
Yes |
hops |
integer |
Yes |
percent |
string / null |
Yes |
source |
string / null |
No |
grade |
"high", "review", "minor", "none" / null |
No |
FeeView
| Field | Type / values | Required |
|---|---|---|
value |
string |
Yes |
minor |
string |
Yes |
rule |
"seller-share-v1" |
Yes |
FieldComparisonResponse
| Field | Type / values | Required |
|---|---|---|
expected |
string / null |
Yes |
actual |
string / null |
Yes |
result |
"MATCH", "MISMATCH", "NOT_EVALUATED", "INSUFFICIENT" |
Yes |
FreshnessResponse
| Field | Type / values | Required |
|---|---|---|
checked_at |
string |
Yes |
transaction_at |
string / null |
Yes |
risk_data_at |
string / null |
Yes |
token_data_at |
string / null |
Yes |
max_source_age_seconds |
integer |
Yes |
FundingView
| Field | Type / values | Required |
|---|---|---|
received |
Money |
Yes |
remaining |
Money |
Yes |
InstructionResponse
| Field | Type / values | Required |
|---|---|---|
version |
integer |
Yes |
network |
string |
Yes |
recipient |
string / null |
Yes |
sender |
string / null |
Yes |
token_contract |
string / null |
Yes |
amount |
string / null |
Yes |
amount_tolerance |
string / null |
Yes |
effective_at |
string / null |
Yes |
approval_reference |
string / null |
Yes |
source |
string |
Yes |
history_complete |
boolean |
Yes |
created_at |
string |
Yes |
redacted |
boolean |
Yes |
IntegrityComparisonsResponse
| Field | Type / values | Required |
|---|---|---|
recipient |
FieldComparisonResponse / null |
Yes |
sender |
FieldComparisonResponse / null |
Yes |
token |
FieldComparisonResponse / null |
Yes |
amount |
AmountComparisonResponse / null |
Yes |
network |
FieldComparisonResponse |
Yes |
IntegrityResponse
| Field | Type / values | Required |
|---|---|---|
status |
"MATCH", "MISMATCH", "AMBIGUOUS", "NOT_EVALUATED", "INSUFFICIENT" |
Yes |
selected_event_ref |
string / null |
Yes |
relevant_event_count |
integer |
Yes |
comparisons |
IntegrityComparisonsResponse |
Yes |
Links
| Field | Type / values | Required |
|---|---|---|
buyer |
string |
Yes |
seller |
string |
Yes |
telegram_invite |
string / null |
Yes |
LookupRequest
| Field | Type / values | Required |
|---|---|---|
external_reference |
string |
Yes |
ModuleStatusResponse
| Field | Type / values | Required |
|---|---|---|
key |
"sanctions_aml", "wallet_behaviour", "token_authenticity", "contract_controls", "address_security", "counterparties_services", "flows_connections" |
Yes |
status |
"RISK_DETECTED", "NO_MATCHES_FOUND", "PARTIALLY_CHECKED", "INSUFFICIENT_DATA", "NOT_SUPPORTED", "NOT_CHECKED" |
Yes |
source_coverage |
"complete", "partial", "none", "not_applicable" |
Yes |
Money
| Field | Type / values | Required |
|---|---|---|
value |
string |
Yes |
minor |
string |
Yes |
NetworkErrorDetail
| Field | Type / values | Required |
|---|---|---|
code |
string |
Yes |
message |
string |
Yes |
retryable |
boolean |
Yes |
required_field |
"network" |
Yes |
candidates |
"tron", "eth", "ton"[] |
Yes |
checked_networks |
"tron", "eth", "ton"[] |
Yes |
NetworkInputErrorResponse
| Field | Type / values | Required |
|---|---|---|
request_id |
string |
Yes |
network |
null |
No |
state |
"insufficient_input" |
No |
error |
NetworkErrorDetail |
Yes |
NewVersionRequest
| Field | Type / values | Required |
|---|---|---|
buyer |
string |
Yes |
seller |
string |
Yes |
amount |
string |
Yes |
category |
Category |
Yes |
title |
string |
Yes |
description |
string |
No |
delivery |
DeliveryInput |
Yes |
timeline |
TimelineInput |
Yes |
resolver_enabled |
boolean |
No |
resolver_id |
string / null |
No |
resolver_fee |
string / null |
No |
expected_version |
integer |
Yes |
NobodyActs
| Field | Type / values | Required |
|---|---|---|
at |
string / null |
Yes |
outcome |
"EXPIRED", "REFUNDED", "RELEASED", "DEADLOCK", "AGREEMENT_EXPIRED" |
Yes |
claim_by |
"BUYER", "SELLER", "ANYONE" / null |
Yes |
NoteRequest
| Field | Type / values | Required |
|---|---|---|
purpose |
"DELIVERY", "DISPUTE", "RESPONSE", "OTHER" |
Yes |
note |
string |
Yes |
supersedes |
string / null |
No |
ObligationLookupRequest
| Field | Type / values | Required |
|---|---|---|
external_reference |
string |
Yes |
ObligationRequest
| Field | Type / values | Required |
|---|---|---|
network |
"tron", "eth", "ton" |
Yes |
expected_recipient |
string / null |
No |
expected_token |
string / null |
No |
expected_amount |
string / null |
No |
expected_sender |
string / null |
No |
amount_tolerance |
string / null |
No |
external_reference |
string |
Yes |
direction |
"INCOMING", "OUTGOING" / null |
No |
workflow_type |
"PAYOUT", "DEPOSIT", "INVOICE", "REFUND", "SETTLEMENT", "OTHER" / null |
No |
instruction_version |
integer / null |
No |
instruction_effective_at |
string / null |
No |
approval_reference |
string / null |
No |
ObligationResponse
| Field | Type / values | Required |
|---|---|---|
external_reference |
string / null |
Yes |
environment |
"live", "sandbox" |
Yes |
workflow_type |
string / null |
Yes |
direction |
string / null |
Yes |
status |
string |
Yes |
current_instruction_version |
integer / null |
Yes |
expected_amount |
string / null |
Yes |
allocated_amount |
string |
Yes |
residual_amount |
string / null |
Yes |
pending_events |
integer |
Yes |
instructions |
InstructionResponse[] |
Yes |
attempts |
AttemptResponse[] |
Yes |
allocations |
AllocationResponse[] |
Yes |
decisions |
DecisionSummaryResponse[] |
Yes |
created_at |
string |
Yes |
redacted |
boolean |
Yes |
ObligationSummaryResponse
| Field | Type / values | Required |
|---|---|---|
external_reference |
string / null |
Yes |
workflow_type |
string / null |
Yes |
direction |
string / null |
Yes |
instruction_version |
integer / null |
Yes |
status |
"OPEN", "PARTIALLY_ALLOCATED", "ALLOCATED", "OVER_ALLOCATED", "CANCELLED" |
Yes |
expected_amount |
string / null |
Yes |
allocated_amount |
string |
Yes |
residual_amount |
string / null |
Yes |
attempts |
integer |
Yes |
events |
integer |
Yes |
pending_events |
integer |
Yes |
redacted |
boolean |
No |
OutcomeRequest
| Field | Type / values | Required |
|---|---|---|
owner |
string / null |
No |
outcome_status |
"CONFIRMED", "DISPUTED", "UNRESOLVED", "UNKNOWN" |
Yes |
loss_prevented |
"CONFIRMED", "NOT_CONFIRMED", "UNKNOWN" |
No |
outcome_at |
string / null |
No |
Parties
| Field | Type / values | Required |
|---|---|---|
buyer |
string |
Yes |
seller |
string |
Yes |
PartyMoney
| Field | Type / values | Required |
|---|---|---|
buyer |
Money |
Yes |
seller |
Money |
Yes |
fee |
Money |
Yes |
resolver |
Money |
Yes |
ReasonCode
| Field | Type / values | Required |
|---|
ReasonResponse
| Field | Type / values | Required |
|---|---|---|
code |
ReasonCode |
Yes |
category |
"transaction", "risk", "sanctions", "token", "expected", "integrity", "ledger", "context" |
Yes |
severity |
"info", "warning", "high", "critical" |
Yes |
RedeliveryResponse
| Field | Type / values | Required |
|---|---|---|
delivery_id |
string |
Yes |
status |
string |
Yes |
ResolutionRequest
| Field | Type / values | Required |
|---|---|---|
owner |
string / null |
No |
resolution |
"ACCEPTED", "ACCEPTED_AFTER_REVIEW", "REJECTED", "REFUNDED", "CORRECTED", "WRITTEN_OFF", "OTHER" |
Yes |
resolved_at |
string / null |
No |
ResolverListResponse
| Field | Type / values | Required |
|---|---|---|
resolvers |
ResolverResponse[] |
Yes |
ResolverRegistration
| Field | Type / values | Required |
|---|---|---|
address |
string |
Yes |
name |
string |
Yes |
affiliation |
"PLATFORM", "INDEPENDENT" |
Yes |
rules_version |
string |
Yes |
rules_sha256 |
string |
Yes |
ResolverResponse
| Field | Type / values | Required |
|---|---|---|
id |
string |
Yes |
network |
string |
Yes |
address |
string |
Yes |
name |
string |
Yes |
affiliation |
"PLATFORM", "INDEPENDENT" |
Yes |
rules_version |
string |
Yes |
rules_sha256 |
string |
Yes |
status |
"ACTIVE", "DISABLED" |
Yes |
owned |
boolean |
Yes |
key_scheme |
"SINGLE_KEY", "MULTISIG_2_OF_3", "UNSUPPORTED" / null |
Yes |
signatures_required |
integer / null |
Yes |
checked_at |
string / null |
Yes |
eligible |
boolean |
Yes |
ineligible_reason |
string / null |
Yes |
ResolverView
| Field | Type / values | Required |
|---|---|---|
id |
string |
Yes |
name |
string |
Yes |
address |
string |
Yes |
affiliation |
"PLATFORM", "INDEPENDENT" |
Yes |
rules_version |
string |
Yes |
rules_sha256 |
string |
Yes |
fee |
Money |
Yes |
key_scheme |
"SINGLE_KEY", "MULTISIG_2_OF_3", "UNSUPPORTED" / null |
Yes |
signatures_required |
integer / null |
Yes |
verified |
boolean |
Yes |
registered_by |
"PLATFORM", "OPERATOR" |
Yes |
ReuseResponse
| Field | Type / values | Required |
|---|---|---|
status |
"FIRST_SEEN", "REPEAT_CHECK", "SAME_OBLIGATION", "DECLARED_SHARED", "OTHER_OBLIGATION" |
Yes |
other_obligations |
integer |
Yes |
prior_decisions |
integer |
Yes |
first_seen_at |
string / null |
Yes |
ReversalRequest
| Field | Type / values | Required |
|---|---|---|
reason |
"CUSTOMER_CORRECTION", "DISPUTED", "DUPLICATE_RECORD", "OTHER" |
Yes |
owner |
string / null |
No |
RiskSummaryResponse
| Field | Type / values | Required |
|---|---|---|
status |
"HIGH_RISK", "REVIEW", "NO_MATERIAL_SIGNAL", "NOT_EVALUATED", "INSUFFICIENT" |
Yes |
driver |
ReasonCode / null |
Yes |
driver_evidence_ids |
string[] |
Yes |
RulingView
| Field | Type / values | Required |
|---|---|---|
buyer_amount |
Money / null |
Yes |
rationale |
string |
Yes |
ruling_hash |
string |
Yes |
status |
string |
Yes |
txid |
string / null |
Yes |
SettlementView
| Field | Type / values | Required |
|---|---|---|
buyer_proposal |
Money / null |
Yes |
seller_proposal |
Money / null |
Yes |
deadlocked |
boolean |
Yes |
SimpleCheckRequest
| Field | Type / values | Required |
|---|---|---|
network |
"tron", "eth", "ton" / null |
No |
expected_recipient |
string / null |
No |
expected_token |
string / null |
No |
expected_amount |
string / null |
No |
expected_sender |
string / null |
No |
amount_tolerance |
string / null |
No |
tx_hash |
string |
Yes |
SimpleCheckResponse
| Field | Type / values | Required |
|---|---|---|
request_id |
string |
Yes |
network |
"tron", "eth", "ton" |
Yes |
state |
"clear", "review", "high_risk", "limited_data" |
Yes |
risk_level |
"low", "moderate", "high", "severe", "unknown" |
Yes |
coverage |
"complete", "partial" |
Yes |
reason_codes |
string[] |
Yes |
environment |
"live", "sandbox" |
No |
details |
CheckDetails |
Yes |
SourceCoverageResponse
| Field | Type / values | Required |
|---|---|---|
sanctions_sources |
object |
Yes |
transaction_sources |
object |
Yes |
risk_sources |
object |
Yes |
universal_clearance |
false |
No |
SourceObservationResponse
| Field | Type / values | Required |
|---|---|---|
status |
"checked", "checked_stale", "checked_freshness_unknown", "not_checked", "not_applicable", "unavailable", "partial", "disagreement" |
Yes |
checked_at |
string / null |
Yes |
retrieved_at |
string / null |
Yes |
data_updated_at |
string / null |
Yes |
stale_after_seconds |
integer / null |
Yes |
scope |
string |
Yes |
error_code |
string / null |
Yes |
StatusDriversResponse
| Field | Type / values | Required |
|---|---|---|
transaction |
ReasonCode / null |
Yes |
integrity |
ReasonCode / null |
Yes |
risk |
ReasonCode / null |
Yes |
coverage |
ReasonCode / null |
Yes |
action |
ReasonCode / null |
Yes |
TermsView
| Field | Type / values | Required |
|---|---|---|
version |
integer |
Yes |
agreed_version |
integer / null |
Yes |
terms_hash |
string / null |
Yes |
deal_id |
string / null |
Yes |
agreement_expires_at |
string / null |
Yes |
consents |
ConsentsView |
Yes |
TimelineInput
| Field | Type / values | Required |
|---|---|---|
agreement_window_seconds |
integer / null |
No |
funding_window_seconds |
integer / null |
No |
delivery_period_seconds |
integer |
Yes |
inspection_period_seconds |
integer |
Yes |
resolve_period_seconds |
integer / null |
No |
TimelineView
| Field | Type / values | Required |
|---|---|---|
funding_deadline |
string / null |
Yes |
delivery_period_seconds |
integer / null |
Yes |
inspection_period_seconds |
integer / null |
Yes |
resolve_period_seconds |
integer / null |
Yes |
funded_at |
string / null |
Yes |
delivered_at |
string / null |
Yes |
disputed_at |
string / null |
Yes |
settled_at |
string / null |
Yes |
current_deadline |
string / null |
Yes |
resolve_deadline |
string / null |
Yes |
if_nobody_acts |
NobodyActs / null |
Yes |
TransactionAccepted
| Field | Type / values | Required |
|---|---|---|
txid |
string |
Yes |
status |
string |
Yes |
TransactionCheckRequest
| Field | Type / values | Required |
|---|---|---|
network |
"tron", "eth", "ton" |
Yes |
expected_recipient |
string / null |
No |
expected_token |
string / null |
No |
expected_amount |
string / null |
No |
expected_sender |
string / null |
No |
amount_tolerance |
string / null |
No |
tx_hash |
string |
Yes |
direction |
"INCOMING", "OUTGOING" / null |
No |
workflow_type |
"PAYOUT", "DEPOSIT", "INVOICE", "REFUND", "SETTLEMENT", "OTHER" / null |
No |
external_reference |
string / null |
No |
instruction_version |
integer / null |
No |
instruction_effective_at |
string / null |
No |
approval_reference |
string / null |
No |
attempt_reference |
string / null |
No |
customer_context |
CustomerContext / null |
No |
TransactionCheckResponse
| Field | Type / values | Required |
|---|---|---|
request_id |
string |
Yes |
tx_hash |
string |
Yes |
network |
"tron", "eth", "ton" |
Yes |
transaction_type |
string |
Yes |
transaction_category |
"eth_transfer", "erc20_transfer", "ton_transfer", "jetton_transfer", "trx_transfer", "trc10_transfer", "trc20_transfer", "smart_contract_call", "smart_contract_deploy", "staking", "voting", "governance", "resource_operation", "account_operation", "exchange", "market", "permission_update", "other", "unknown" |
Yes |
transaction_state |
"confirmed", "pending", "failed", "not_found", "unknown" |
Yes |
confirmations |
integer / null |
Yes |
required_confirmations |
integer |
Yes |
sender |
string / null |
Yes |
recipient |
string / null |
Yes |
token_contract |
string / null |
Yes |
token_symbol |
string / null |
Yes |
decimals |
integer / null |
Yes |
amount |
string / null |
Yes |
transfers |
TransferResponse[] |
Yes |
transfers_truncated |
boolean |
Yes |
aml_risk_level |
"low", "moderate", "high", "severe", "unknown" |
Yes |
schema_version |
"0.3" |
Yes |
policy_version |
string |
Yes |
sanctions_hit |
boolean / null |
Yes |
direct_sanctions_match |
boolean / null |
Yes |
indirect_sanctions_exposure |
boolean / null |
Yes |
risk_exposure |
boolean / null |
Yes |
key_exposure |
ExposureResponse[] |
Yes |
token_authenticity |
"official", "fake", "unknown" |
Yes |
recipient_match |
boolean / null |
Yes |
token_match |
boolean / null |
Yes |
amount_match |
boolean / null |
Yes |
coverage |
"complete", "partial" |
Yes |
workflow_coverage |
"complete", "partial" |
Yes |
source_coverage |
SourceCoverageResponse |
Yes |
freshness |
FreshnessResponse |
Yes |
overall_state |
"CLEAR", "REVIEW", "HIGH_RISK", "LIMITED_DATA" |
Yes |
environment |
"live", "sandbox" |
No |
reasons |
ReasonResponse[] |
Yes |
decision_id |
string / null |
Yes |
direction |
"INCOMING", "OUTGOING" / null |
Yes |
workflow_type |
"PAYOUT", "DEPOSIT", "INVOICE", "REFUND", "SETTLEMENT", "OTHER" / null |
Yes |
versions |
VersionsResponse |
Yes |
transaction_status |
"CONFIRMED", "PENDING", "FAILED", "NOT_FOUND", "INSUFFICIENT" |
Yes |
integrity_status |
"MATCH", "MISMATCH", "AMBIGUOUS", "NOT_EVALUATED", "INSUFFICIENT" |
Yes |
risk_status |
"HIGH_RISK", "REVIEW", "NO_MATERIAL_SIGNAL", "NOT_EVALUATED", "INSUFFICIENT" |
Yes |
coverage_status |
"OK", "DEGRADED", "UNAVAILABLE", "DISAGREEMENT", "SKIPPED" |
Yes |
status_drivers |
StatusDriversResponse |
Yes |
result_final |
boolean |
Yes |
verification_final |
boolean |
Yes |
risk_final |
boolean |
Yes |
risk_retryable |
boolean |
Yes |
risk_retry_after_seconds |
integer / null |
Yes |
retryable |
boolean |
Yes |
retry_after_seconds |
integer / null |
Yes |
recommended_action |
"PROCEED", "CONFIRM_INTERNAL_STATE", "MANUAL_REVIEW", "RECHECK_LATER", "NOT_EXECUTED", "HOLD_AND_ESCALATE" |
Yes |
integrity |
IntegrityResponse |
Yes |
risk |
RiskSummaryResponse |
Yes |
evidence_items |
EvidenceItemResponse[] |
Yes |
coverage_limitations |
CoverageLimitationsResponse |
Yes |
obligation |
ObligationSummaryResponse / null |
No |
reuse |
ReuseResponse / null |
No |
TransactionReport
| Field | Type / values | Required |
|---|---|---|
role |
"BUYER", "SELLER" |
Yes |
action |
"APPROVE_TERMS", "TRANSFER_FUNDS", "CONFIRM_FUNDING", "MARK_DELIVERED", "RELEASE", "REFUND", "CLAIM_REFUND", "CLAIM_RELEASE", "DISPUTE", "PROPOSE_SETTLEMENT", "WITHDRAW", "EXPIRE", "SWEEP_EXCESS" |
Yes |
txid |
string |
Yes |
TransactionView
| Field | Type / values | Required |
|---|---|---|
purpose |
string |
Yes |
txid |
string |
Yes |
status |
string |
Yes |
signer_role |
string |
Yes |
block_number |
integer / null |
Yes |
confirmed_at |
string / null |
Yes |
TransferResponse
| Field | Type / values | Required |
|---|---|---|
index |
integer |
Yes |
asset_type |
string |
Yes |
sender |
string / null |
Yes |
recipient |
string / null |
Yes |
token_contract |
string / null |
Yes |
token_id |
string / null |
Yes |
token_symbol |
string / null |
Yes |
decimals |
integer / null |
Yes |
amount |
string / null |
Yes |
event_ref |
string / null |
No |
execution_status |
"success", "failed", "unknown" |
No |
UsageBalanceResponse
| Field | Type / values | Required |
|---|---|---|
granted |
integer |
Yes |
used |
integer |
Yes |
reserved |
integer |
Yes |
available |
integer |
Yes |
UsageBalancesResponse
| Field | Type / values | Required |
|---|---|---|
included |
UsageBalanceResponse |
Yes |
extra |
UsageExtraBalanceResponse |
Yes |
total_available |
integer |
Yes |
computed_at |
string |
Yes |
UsageExtraBalanceResponse
| Field | Type / values | Required |
|---|---|---|
granted |
integer |
Yes |
used |
integer |
Yes |
reserved |
integer |
Yes |
available |
integer |
Yes |
expires_at |
string / null |
Yes |
UsageLimitsResponse
| Field | Type / values | Required |
|---|---|---|
rate_limit_per_minute |
integer |
Yes |
max_concurrent_requests |
integer |
Yes |
enabled_networks |
string[] |
Yes |
UsagePeriodResponse
| Field | Type / values | Required |
|---|---|---|
start |
string |
Yes |
end |
string |
Yes |
used |
integer |
Yes |
reserved |
integer |
Yes |
limit |
integer |
Yes |
remaining |
integer |
Yes |
UsagePlanResponse
| Field | Type / values | Required |
|---|---|---|
code |
string |
Yes |
version |
integer |
Yes |
name |
string |
Yes |
UsageRecentResponse
| Field | Type / values | Required |
|---|---|---|
days |
integer |
Yes |
requests |
integer |
Yes |
billable |
integer |
Yes |
limited_data |
integer |
Yes |
errors |
integer |
Yes |
average_latency_ms |
integer / null |
Yes |
by_network |
object |
Yes |
by_overall_state |
object |
Yes |
by_kind |
object |
No |
UsageResponse
| Field | Type / values | Required |
|---|---|---|
tenant_id |
string |
Yes |
environment |
"live", "sandbox" |
No |
plan |
UsagePlanResponse / null |
Yes |
limits |
UsageLimitsResponse |
Yes |
period |
UsagePeriodResponse |
Yes |
balances |
UsageBalancesResponse |
Yes |
subscription |
UsageSubscriptionResponse |
Yes |
recent |
UsageRecentResponse |
Yes |
UsageSubscriptionResponse
| Field | Type / values | Required |
|---|---|---|
status |
"legacy", "active", "scheduled", "lapsed", "none" |
Yes |
plan_code |
string / null |
Yes |
plan_version |
integer / null |
Yes |
period_start |
string / null |
Yes |
period_end |
string / null |
Yes |
next_period_start |
string / null |
No |
renewal |
"manual" |
No |
cancel_at_period_end |
boolean |
No |
VersionsResponse
| Field | Type / values | Required |
|---|---|---|
decision |
string |
Yes |
rules |
object |
Yes |
reason_codes |
string |
Yes |
evidence_schema |
string |
Yes |
contract |
string |
Yes |
WalletAddressSecurityResponse
| Field | Type / values | Required |
|---|---|---|
denylisted |
boolean / null |
Yes |
denylist_category |
string / null |
Yes |
provider_flagged |
boolean / null |
Yes |
provider_flags |
string[] |
Yes |
issuer_blocked |
boolean / null |
Yes |
issuer_blocked_symbols |
string[] |
Yes |
WalletBehaviourResponse
| Field | Type / values | Required |
|---|---|---|
is_contract |
boolean / null |
Yes |
contract_verified |
boolean / null |
Yes |
transaction_count |
integer / null |
Yes |
transaction_count_limited |
boolean |
Yes |
wallet_age_days |
integer / null |
Yes |
first_activity_at |
string / null |
Yes |
last_activity_at |
string / null |
Yes |
counterparties_count |
integer / null |
Yes |
WalletCheckDetails
| Field | Type / values | Required |
|---|---|---|
schema_version |
"0.1" |
No |
overall_state |
"CLEAR", "REVIEW", "HIGH_RISK", "LIMITED_DATA" |
Yes |
data_coverage |
"FULL", "PARTIAL", "INSUFFICIENT" |
Yes |
coverage_scope |
"supported_deep_sources" |
No |
modules |
ModuleStatusResponse[] |
Yes |
sanctions |
WalletSanctionsResponse |
Yes |
address_security |
WalletAddressSecurityResponse |
Yes |
behaviour |
WalletBehaviourResponse |
Yes |
counterparties |
WalletCounterpartiesResponse |
Yes |
token_authenticity |
WalletTokenAuthenticityResponse |
Yes |
freshness |
WalletFreshnessResponse |
Yes |
source_coverage |
object |
Yes |
universal_clearance |
false |
No |
reasons |
WalletReasonResponse[] |
Yes |
limitations |
string[] |
Yes |
evidence |
WalletEvidenceResponse |
Yes |
WalletCheckRequest
| Field | Type / values | Required |
|---|---|---|
address |
string |
Yes |
network |
"tron", "eth", "ton" / null |
No |
WalletCheckResponse
| Field | Type / values | Required |
|---|---|---|
request_id |
string |
Yes |
address |
string |
Yes |
network |
"tron", "eth", "ton" |
Yes |
state |
"clear", "review", "high_risk", "limited_data" |
Yes |
coverage |
"complete", "partial" |
Yes |
reason_codes |
string[] |
Yes |
environment |
"live", "sandbox" |
No |
details |
WalletCheckDetails |
Yes |
WalletCounterpartiesResponse
| Field | Type / values | Required |
|---|---|---|
screened |
integer |
Yes |
unverified |
integer |
Yes |
flagged |
integer |
Yes |
WalletEvidenceResponse
| Field | Type / values | Required |
|---|---|---|
live |
boolean |
Yes |
source |
"live", "sandbox" |
Yes |
WalletFreshnessResponse
| Field | Type / values | Required |
|---|---|---|
checked_at |
string |
Yes |
analyzed_at |
string / null |
Yes |
served_from_analysis_cache |
boolean |
Yes |
oldest_source_age_seconds |
integer / null |
Yes |
WalletReasonResponse
| Field | Type / values | Required |
|---|---|---|
code |
string |
Yes |
category |
"sanctions", "risk", "address", "token", "counterparties", "behaviour", "coverage" |
Yes |
severity |
"info", "warning", "high", "critical" |
Yes |
WalletSanctionsResponse
| Field | Type / values | Required |
|---|---|---|
direct_match |
boolean / null |
Yes |
authorities |
string[] |
Yes |
attributed |
boolean |
Yes |
indirect_exposure |
boolean / null |
Yes |
exposure_source |
"aml_provider" / null |
Yes |
WalletTokenAuthenticityResponse
| Field | Type / values | Required |
|---|---|---|
total |
integer |
Yes |
official |
integer |
Yes |
fake |
integer |
Yes |
suspicious |
integer |
Yes |
unknown |
integer |
Yes |
WebhookRequest
| Field | Type / values | Required |
|---|---|---|
url |
string |
Yes |
WebhookResponse
| Field | Type / values | Required |
|---|---|---|
url |
string / null |
Yes |
status |
string / null |
Yes |
secret |
string / null |
No |
consecutive_failures |
integer |
No |
Changelog and versioning
2026-10-15: corrections, same policy
The contract stays 0.3 and policy b2b-tx-2026-10.4. Stored replies replay unchanged.
- TRON transfer lists cut short. When both sources list more transfers than ChainZap reads (100), the two lists are no longer compared row by row: each source keeps its own first rows. A list cut on one side only is still a disagreement. The gap stays
TRANSFERS_TRUNCATED, so such a check can become final asLIMITED_DATAinstead of asking for a recheck indefinitely. - Provider rights. A source with no rights on record, or one whose rights keep it internal, shows neither its own evidence reference nor its own exposure fields. No current answer changes.
- Examples. List sources in the examples read as in a live answer, including
unand a checked list's freshness; the reference example carries thereuseobject a recorded check has. - Docs. Which sandbox errors carry
environment; which disagreements maketransaction_statusINSUFFICIENT;CONFIRM_INTERNAL_STATEcloses a payout only with aMATCH, and a payout reachesPROCEEDonly with the obligation'sexternal_referencein the check (orcustomer_context.credit_status: "NOT_CREDITED");ATTEMPT_MAY_STILL_LANDneedsdirection: "OUTGOING"in the request;spend_capis also reported while spend cannot be accounted; comparison codes are withheld whiletransaction_statusisPENDING, and a check whose sources disagree about the transaction itself is not final but can still carry them.
2026-10-14: reference corrections, same policy
The contract stays 0.3 and policy b2b-tx-2026-10.4; no decision rule changed.
- Error codes. The OpenAPI description of
POST /v1/transaction/checknow lists every error code the check can return:ledger_not_enabled(403),instruction_conflict,instruction_version_requiredandattempt_conflict(409),invalid_amount_toleranceandinvalid_reference(422). The codes and their meaning are unchanged; see errors. - Examples. The response example in the reference lists both chain sources and the AML source with the statuses a live answer reports, one evidence item per source, and the reasons a live answer gives. Every example shows timestamps as the API returns them (
…Z). - Docs.
risk_finalisfalsewhile a transaction is pending or not found, whateverrisk_statussays. OnMANUAL_REVIEW,status_drivers.actionnames one finding:TX_REVERTEDon a failed transaction, otherwise the most severe, with a risk-data gap or risk signal before the payment comparison at equal severity. Readstatus_drivers.integrityfor the payment comparison. On the AML source,checked_freshness_unknownis the normal status of a completed screen.
2026-10-14: policy b2b-tx-2026-10.4
Integrity rule int-v3. The contract stays 0.3; stored replies replay unchanged under the policy they were answered with.
- Pending is not compared. While a transaction is pending (
transaction_status: PENDING), noEXPECTED_*_MISMATCHreason is reported, as integrity is alreadyNOT_EVALUATEDwith null match flags. Terms that differ are reported once the transaction is final. - Do not pay again.
ATTEMPT_MAY_STILL_LAND(a check sent withdirection: "OUTGOING"whose transaction is not found) is always kept in the shortreasonslist, whatever else is found. - Docs. Every organization has a daily spend cap on paid sources, and
spend_cap/daily_capreset at 00:00 UTC; the daily ceiling of unbilled checks is 500 by default; quota headers count the check being answered and replays carry none; the sandbox marker on/v1/transaction/checkisenvironment; the failed sandbox fixture is charged; on 0.3 decide on the axes, not onoverall_state; how a payout reachesPROCEED;expected_tokeneverywhere; HTTP status descriptions in the reference are endpoint-neutral and list 413 and 415.
2026-10-14: corrections, same contract
The contract stays 0.3 and policy b2b-tx-2026-10.3; no decision rule changed. Stored replies replay unchanged.
- Wallet check.
address_security.provider_flaggedsays whether the address-security provider flagged the address (nullwhen it did not answer). The provider's own labels are no longer returned: the deprecatedprovider_flagsis["PROVIDER_SECURITY_FLAG"]or empty. When the provider's rights do not let ChainZap show the flag, it isnullwith the limitationaddress_security_provider_withheld. State and reasons do not change. - TRON time.
transaction_at, evidenceeffective_atand, for payments the ledger records from now on, the payment time are the block's time, never the timestamp the sender wrote into the transaction. Payments already in the ledger keep the time first recorded. A transaction not yet in a block hastransaction_at: null. - TRON sources. Two sources that list the same transfers in a different order no longer read as a disagreement.
- Ledger. A reversal waits for a check of the same payment and is never undone by it; under contention it answers
504 request_timeoutwithRetry-After, nothing stored. Ledger operations now list that504. - Contract.
/v1/openapi.jsonis now identical to the published contract, andGET /v1/batches/{batch_id}/export.csvis described as CSV only. - Batches. The guide now says that a row whose only gap is risk is
DONEwithrisk_retryable: true. - Provider rights. An exposure row from a source without rights on record shows none of that source's own fields.
2026-10-10: contract 0.3 finality correction
Policy b2b-tx-2026-10.3 separates payment verification from risk/KYT. verification_final and its alias result_final describe verification; risk_final, risk_retryable and risk_retry_after_seconds describe the risk assessment. A final expected match remains MATCH when KYT is unavailable, with risk_status: INSUFFICIENT and MANUAL_REVIEW. Pending now returns NOT_EVALUATED in integrity and every requested comparison, with null match flags. retryable only requests a new verification observation. Update clients that used it as a combined verification/KYT flag.
The contract stays 0.3. Stored replies and decisions retain their original policy and meaning; a new observation with a new key uses the corrected policy. Historical decision records have null separate finality fields. The quickstart uses the canonical endpoint; all response examples are rendered by the same engine as live checks.
2026-10-05: contract 0.3
POST /v1/transaction/check answers carry schema_version: "0.3" under policy b2b-tx-2026-10.2. Every 0.2 field keeps its meaning; everything below is added.
- Status axes.
transaction_status,integrity_status,risk_statusandcoverage_statuswithstatus_drivers,result_final,retryable,retry_after_secondsandrecommended_action. See status axes. - Structured comparison.
integritywith per-fieldcomparisons, the selectedevent_refand the number of relevant transfers;transfers[].event_refandexecution_status;expected_senderandamount_tolerancein the request. Several transfers to the payee addADDITIONAL_RELEVANT_TRANSFERSorSPLIT_WITHIN_TX. See matching. - Evidence and versions.
evidence_items,coverage_limitations(runtime,product),riskwith its driver and evidence, agradeon everykey_exposurerow, andversions. - Obligation ledger.
external_reference,instruction_version,instruction_effective_at,approval_reference,attempt_reference,direction,workflow_typeandcustomer_context(credit_status,allocation_status) in the request,obligationandreusein the answer, and the/v1/obligations(withPOST /v1/obligations/lookup, so no URL carries a reference),/v1/allocationsand/v1/decisionsendpoints. See obligations and decisions. - Batches.
/v1/batcheschecks a CSV file of up to 200 payments with a free preflight and an estimate, and the developer dashboard has a Batches page. See batches. - Exposure policy
b2b-exp-v2. A provider category ChainZap does not recognise is graded like other risk categories and named (UNRECOGNIZED_PROVIDER_LABEL) instead of being ignored. - Decision id.
decision_ididentifies the answer;request_idstays yours. - Fixes. A reverted transfer no longer reads as a match: its
*_matchfields arenull, and a failed transaction in which nothing executed isNOT_EVALUATEDwithNOT_EXECUTED. The short reason list keeps the comparison and client-context reasons and never exceeds five. Ethereum source disagreements on a transaction's existence or status leave itINSUFFICIENT. - Sandbox. Nibble
dis now a failed transaction;candfstayCLEAR. - Same-day refinements. A failed transaction in which a transfer executed is
integrity_status: INSUFFICIENT, neverMATCH. A check withoutdirectiontakes it from the obligation or fromworkflow_type, and a payment of unknown direction is neverPROCEED. Several transfers to the payee that cannot be told apart always nameAMBIGUOUS_TRANSFER. A check that names anattempt_referencerecorded with another transaction is refused with409 attempt_conflict. Ledger reads have their own rate bucket. An exposure row whose share its source does not allow showing haspercent: null.
POST /v1/check returns the same assessment under details. Idempotency keys used before this change keep returning their stored 0.2 answers.
2026-10-03: contract 0.2
POST /v1/transaction/check answers carry schema_version: "0.2" and policy_version, the decision policy that produced the answer. What changed in that policy:
- Provider-reported exposure moves the state by hops and share instead of by presence: sanctions exposure gives
HIGH_RISKonly at 1 hop or closer and at least 5%,REVIEWwhen it needs a look, andSANCTIONS_EXPOSURE_MINORotherwise; other categories giveREVIEWonly up to 2 hops with at least 1% or an unknown share, or on a hacking event (RISK_EXPOSURE_MINORotherwise). Every row stays inkey_exposure. See coverage. - A sanctions list past its freshness window gives
SANCTIONS_DATA_STALEandLIMITED_DATA; the UN list isnot_applicable. - Only final answers are charged: a pending transaction is free.
- The short reason list always keeps the reason that decided the state and every
EXPECTED_*reason. - An
expected_amountwith zeros beyond the token's decimals is accepted. - An oversized body answers
413 payload_too_largeinstead of422. - Pilot organizations must send all three
expected_*fields (422 expected_fields_required) for official USDT on TRON (422 token_not_enabled); wallet checks are outside the pilot (403 check_kind_not_enabled). - Sandbox nibble
eis now a pending transaction, and the sandbox no longer claims to pick a network from the hash shape.
Idempotency keys used before this change return 409 idempotency_conflict.
2026-10-02: payment through OxaPay
Plans and extra checks are paid in cryptocurrency through OxaPay: the order links to an OxaPay payment page for the exact US dollar total. Crypto Pay and direct TON transfers are no longer offered; orders placed with them keep their history. The checkout no longer asks for an asset. See plans and payment.
2026-09-23: neutral source names
Every data source in a check response is now named by its role, never by the vendor behind it. source_coverage.risk_sources carries aml_provider; transaction_sources keys are chain_explorer, chain_node and chain_node_secondary; the wallet check's source_coverage uses aml_provider and address_security_provider, sanctions.exposure_source is aml_provider, and the AML limitations are aml_provider_unavailable and aml_provider_skipped_dominant_local_hit. Status vocabularies, states and reason codes are unchanged. Integrations that keyed on earlier vendor-specific source names must read sources by role; those names are not returned.
2026-09-21: wallet checks
POST /v1/wallet/check screens one wallet address under the same key, quota and idempotency rules as the transaction check. The network is read from the address format. The response is a state, a coverage level and reason codes with per-module facts; no numeric score is published. A wallet check is billed when a state is produced; limited_data is free. GET /v1/usage adds recent.by_kind. The sandbox gains pinned wallet fixtures and the Playground gains a wallet mode. See wallet check.
2026-09-10: self-serve sign-in
Anyone can sign in to the developer dashboard with a Google account; an organization is created automatically and the first member becomes its owner. An invitation code is optional and only joins an existing organization. TRON and TON mainnet checks are live for new organizations; Ethereum checks are activated by support. Plans and extra checks are bought on the Plan and billing page.
2026-09-08: beta pricing, purchases and sandbox
GET /v1/catalog publishes the BETA_PRICING_V0 plans. GET /v1/usage adds balances, subscription and environment; period.remaining keeps its meaning. Check responses add environment and the X-Quota-Available header. Plans and extra checks packages are bought in the developer dashboard with Crypto Pay or a direct TON transfer, with manual renewal; see plans and payment. Sandbox keys (cz_test_) return deterministic test results without provider calls; see sandbox. Owner, admin and billing members can buy in the dashboard.
2026-09-07: three networks and a simpler check
POST /v1/check accepts a transaction hash with optional network context. It adds conservative network discovery, a short assessment and full evidence in details. TRON, Ethereum mainnet and TON mainnet have separate facts and finality policies. The original check endpoint and the usage endpoint remain available under the same organization limits and idempotency rules.
Unclassified TON contract value now requires partial coverage, including when other transfers are recognized or facts come from cache. Known high risks remain visible.
Ethereum checks are activated per organization by support after live provider acceptance; check service status for the current adapter state.
v1.0.0
TRON transaction checks and organization usage reporting. The developer dashboard provides API key management, plan details and a Playground page for testing requests within your organization.
Ethereum and TON are accepted by the schema; their adapters require separate activation and live acceptance. No wallet API, webhooks, monitoring or payment execution is part of this version.
Contract evolution
The public endpoint prefix is /v1. This documentation is versioned at /docs/v1/. The downloadable OpenAPI is generated from the same request and response models as the API and checked against a committed snapshot in CI.
Integrations should tolerate additional response fields while validating the fields they consume. Do not assume that an unknown reason code means a clean result. Breaking changes require a versioned migration guide; documentation links for the existing major version remain stable.
Service status and support
Access status
The public status indicator reports whether business access is enabled. It does not run a live provider check and is not an uptime guarantee. An available network describes supported functionality; an individual organization may have narrower entitlements.
A 503 api_disabled response means business checks have not been enabled or have been deliberately paused. A 503 provider_unavailable response means the required transaction data could not be retrieved for that request. Preserve the request ID and follow the retry guidance.
Contact
Contact the ChainZap team for Ethereum activation, Scale plan terms, incident questions and support. Include X-Request-ID, the public error code and the UTC time. Never include API keys, identity tokens or raw transaction or provider payloads.
Networks: TRON mainnet is live for every organization and is the scope of the design-partner pilot (USDT TRC-20). TON mainnet is a preview: it answers, but a TON check of an executed transaction currently returns LIMITED_DATA (not charged) because no configured TON sanctions list holds addresses, and it is outside the pilot. Ethereum is implemented and activated per organization by support. /status.json reports configured adapter activation separately from global API access, without live provider probes.
Loading…