Transaction checks
A transaction check screens one transaction from the point of view of your customer: the money they received in a deposit, or the money they are sending in a withdrawal. It uses the same endpoint, the same scope (checks:write) and the same verdict as an address check, so read that page for every field of the response.
Request
| Field | Required | Description |
|---|---|---|
subject | yes | "transaction". |
asset | yes | An asset symbol exactly as listed in Supported assets. |
tx_hash | yes | The transaction hash, at most 160 characters. Its shape must be valid for the asset. |
direction | yes | "deposit" when your customer receives the funds, "withdrawal" when your customer sends them. |
address | sometimes | Your customer's address in the transaction, at most 160 characters. See the next section. |
Unknown fields are rejected. As with every check, send an Idempotency-Key so a retry cannot screen or charge twice; see Idempotency.
The customer's address
address is your customer's address in the transaction: the recipient of a deposit, the sender of a withdrawal.
- On TRX, ETH, BNB and BASE you may leave it out. The API reads the transaction and uses the recipient for a
depositand the sender for awithdrawal. Quota, balance and capacity are checked first, so a refused account drives no lookups. - On every other asset it is required, and a request without it answers
422ADDRESS_REQUIRED. Supported assets shows the assets that can derive it. - Sandbox keys always need it. A transaction check under a sandbox key without
addressalso answersADDRESS_REQUIRED; see Sandbox and live. - If you send it, it is used as given. Nothing is derived.
The verdict pins the address that was used: the address field of the response, the evidence report and a rederive all carry it, whether you sent it or the API derived it. Check the address field against your own records if you rely on the derived value.
When the address is left out and the transaction cannot be read, the request answers 422 TRANSACTION_UNRESOLVED. That happens when the hash does not exist on that network, when the recipient of a deposit cannot be decoded, or when the chain data source did not answer in time. Nothing is accepted and nothing is charged. Check the hash and the network, retry, or send the address yourself.
Examples
A TRON deposit with the address left out, and an Ethereum withdrawal with the address supplied.
- curl
- Node.js
- Python
# TRON deposit, address derived from the transaction
curl -s -X POST https://api.leeri.ai/v1/checks \
-H "Authorization: Bearer $LEERI_API_KEY" \
-H "Idempotency-Key: deposit-2291" \
-H "Content-Type: application/json" \
-d '{"subject":"transaction","asset":"TRX","tx_hash":"'"$TX_HASH"'","direction":"deposit"}'
# Ethereum withdrawal, address supplied
curl -s -X POST https://api.leeri.ai/v1/checks \
-H "Authorization: Bearer $LEERI_API_KEY" \
-H "Idempotency-Key: payout-5530" \
-H "Content-Type: application/json" \
-d '{"subject":"transaction","asset":"ETH","tx_hash":"'"$ETH_TX_HASH"'","direction":"withdrawal","address":"'"$ADDRESS"'"}'
async function checkTransaction(body, idempotencyKey) {
const response = await fetch('https://api.leeri.ai/v1/checks', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LEERI_API_KEY}`,
'Idempotency-Key': idempotencyKey,
'Content-Type': 'application/json',
},
body: JSON.stringify({ subject: 'transaction', ...body }),
});
const payload = await response.json();
if (response.status === 422) {
const code = payload.errors[0].code;
if (code === 'TRANSACTION_UNRESOLVED') throw new Error('transaction not readable: check the hash and network, or send the address');
if (code === 'ADDRESS_REQUIRED') throw new Error('this asset needs the customer address');
}
return payload.data;
}
// TRON deposit, address derived from the transaction
await checkTransaction({ asset: 'TRX', tx_hash: txHash, direction: 'deposit' }, 'deposit-2291');
// Ethereum withdrawal, address supplied
await checkTransaction({ asset: 'ETH', tx_hash: ethTxHash, direction: 'withdrawal', address }, 'payout-5530');
import os
import requests
def check_transaction(body, idempotency_key):
response = requests.post(
"https://api.leeri.ai/v1/checks",
headers={
"Authorization": f"Bearer {os.environ['LEERI_API_KEY']}",
"Idempotency-Key": idempotency_key,
},
json={"subject": "transaction", **body},
timeout=30,
)
payload = response.json()
if response.status_code == 422:
code = payload["errors"][0]["code"]
if code == "TRANSACTION_UNRESOLVED":
raise RuntimeError("transaction not readable: check the hash and network, or send the address")
if code == "ADDRESS_REQUIRED":
raise RuntimeError("this asset needs the customer address")
return payload["data"]
# TRON deposit, address derived from the transaction
check_transaction({"asset": "TRX", "tx_hash": tx_hash, "direction": "deposit"}, "deposit-2291")
# Ethereum withdrawal, address supplied
check_transaction({"asset": "ETH", "tx_hash": eth_tx_hash, "direction": "withdrawal", "address": address}, "payout-5530")
What the response adds
The response is the same CheckView an address check returns, so status can be completed or pending; see Pending and polling. For a transaction check these fields are filled:
| Field | Meaning |
|---|---|
subject | transaction. |
tx_hash | The transaction that was screened. |
direction | deposit or withdrawal, as you sent it. |
address | The customer address that was used, sent or derived. |
amount | The amount of the transaction as a decimal string, never a float. null when it is not known. |
risky_volume_usd | The USD value of the transaction's flow that was tied to risky counterparties, as a decimal string. null until the check completes. |
Checking an address you were already charged for on the same chain in the last 7 days is free, also when you screen it as a transaction; see Rate limits and quotas.
Errors
Everything in Address checks applies, plus:
| Status | Code | When |
|---|---|---|
422 | ADDRESS_REQUIRED | address left out for an asset that cannot derive it, or under a sandbox key. |
422 | TRANSACTION_UNRESOLVED | address left out and the transaction could not be read. Never charged. |
400 | VALIDATION_ERROR | A tx_hash, direction or address with an invalid shape, or an unknown field. |
Items of a batch always send address, because a batch is accepted without reading any chain.