API reference
The REST contract for programmatic screening, published before the service goes live so you can review it before writing code against it.
The ARGUS API returns the same verdict the site renders: a live sanctions screening result, an exposure breakdown, and the signals behind the score, as one JSON object per address. It is designed for the moment before funds move — screen an address at payment time, act on the response, keep the object as your audit record.
This page is the published contract, not a running service. The base URL does not serve requests yet and no keys are being issued. It is public now so integrators can review the shapes before the endpoints exist — if something here would not work for you, that is exactly what we want to hear. Ask for early access and we will contact you when keys are available.
Base URL and authentication
All endpoints are served over HTTPS from a single base URL and are versioned in the path. Every request must carry an API key as a Bearer token; there are no unauthenticated endpoints.
https://api.argus.exampleAuthorization: Bearer <your key>
Accept: application/jsonKeys are secrets. Send them from a server, never from a browser — a key shipped to a client is public the moment the page loads.
Screen an address
Screens one address and returns a full verdict. The address path parameter is the only input: an EVM address (0x plus 40 hex characters) or a TRON address (T plus 33 base58 characters). The network is inferred from the shape — an EVM address is the same string on every EVM chain, so screening it once covers all of them.
curl https://api.argus.example/v1/screen/TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t \
-H "Authorization: Bearer $ARGUS_API_KEY"const address = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t";
const res = await fetch(`https://api.argus.example/v1/screen/${address}`, {
headers: { Authorization: `Bearer ${process.env.ARGUS_API_KEY}` },
});
if (!res.ok) throw new Error(`Screening failed: ${res.status}`);
const verdict: ScreenResult = await res.json();
if (verdict.sanctions.hit !== null) {
// Designated. Decisive on its own — decline before funds move.
}type Band = "clear" | "caution" | "high" | "severe";
interface SanctionsHit {
name: string; // the designated person or entity
uid: number | null; // OFAC's SDN entry id
type: string; // "Individual" | "Entity"
asset: string; // ticker OFAC recorded the address under
programs: string[]; // e.g. ["DPRK3", "CYBER2"]
}
interface ScreenResult {
address: string;
network: "evm" | "tron";
score: number | null; // 0–100; null when no score is justified
band: Band | null; // clear <30 · caution <55 · high <75 · severe
sanctions: {
hit: SanctionsHit | null; // null = screened and not found,
// never "not screened"
publishDate: string; // OFAC's own date, MM/DD/YYYY
addressCount: number; // addresses in the screened snapshot
sourceUrl: string;
};
exposure: {
label: string; // source category, e.g. "Mixer"
share: number; // percentage of inbound value
band: Band | "unknown";
}[];
signals: {
title: string;
detail: string;
band: Band | "unknown";
}[];
// true while exposure and signals carry sample figures pending the
// graph indexer; the sanctions block is live regardless
exposureIsIllustrative: boolean;
}{
"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"network": "tron",
"score": null,
"band": null,
"sanctions": {
"hit": null,
"publishDate": "08/20/2026",
"addressCount": 961,
"sourceUrl": "https://ofac.treasury.gov/sanctions-list-service"
},
"exposure": [
{ "label": "Major exchange", "share": 61.4, "band": "clear" },
{ "label": "Unattributed", "share": 12.6, "band": "unknown" }
],
"signals": [
{
"title": "Majority of inbound value from a regulated venue",
"detail": "61.4% · withdrawal pattern consistent with retail",
"band": "clear"
}
],
"exposureIsIllustrative": true
}Why score can be null. A composite score needs the exposure, behaviour and attribution layers, and those are not live yet. Fabricating a number anyway would produce the one thing a screening tool must never do: contradict itself — "hit": null in the sanctions block beside an invented "score": 94 reads as a random number generator, and costs more trust than an empty field ever would. So the score is present only when a live layer justifies it: a direct OFAC designation returns 100 and "severe", and a designated counterparty found at one hop returns a high score with the finding in signals. Otherwise both score and band are null, and your integration should treat that as “not scored”, not as “low risk”.
The same honesty applies to sanctions.hit: null — it means the address was screened against the snapshot and not found, and the publishDate beside it tells you which snapshot. A designation made after that date would not appear. While exposureIsIllustrative is true, the exposure and signal arrays carry sample figures and must not drive decisions.
Batch screening
Screens up to 100 addresses in one request. Networks can be mixed. Results come back in input order, and an entry that fails validation is returned as an error object in its slot rather than failing the whole batch — one typo should not void the 99 verdicts beside it.
curl -X POST https://api.argus.example/v1/screen/batch \
-H "Authorization: Bearer $ARGUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"addresses": [
"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"0xdAC17F958D2ee523a2206206994597C13D831ec7"
]
}'{
"results": [
{ "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "…": "…" },
{
"error": {
"code": "invalid_address",
"message": "TRON address failed base58check."
}
}
]
}Each address in a batch is metered as one call. Batches over 100 entries are rejected with 400 invalid_request rather than truncated silently.
Errors
Errors are JSON with a stable machine-readable code; the message is for humans and may change.
{
"error": {
"code": "invalid_address",
"message": "TRON address failed base58check — likely a typo."
}
}The address fails validation. EVM must match 0x plus 40 hex characters. TRON must be base58 and pass the full base58check checksum — the site's own input validates shape only, so a TRON typo can look plausible right up to the checksum; the API rejects it here rather than screening the wrong address.
The body is not valid JSON, addresses is empty, or a batch exceeds 100 entries.
The API key is missing, malformed, or revoked.
No such route or version. Never used for a valid address with no history — an address that has never transacted is a normal 200 result, not an error.
Over the per-key limit. The Retry-After header says when to try again.
A chain data source is down or timed out. Sanctions screening runs against a local snapshot, so it degrades last. Safe to retry with backoff; screening reads are idempotent.
Rate limits and metering
API access is part of the API plan on the pricing page: $0.04 per call, volume pricing from 50,000 calls, unlimited batch screening. The limits below are part of this specification — published for review like everything else here, and confirmed at launch.
Exceeding a limit returns 429 rate_limited with a Retry-After header. Limits apply per key, not per IP.
Webhooks
Screening an address once tells you about that moment. The list moves afterwards: OFAC publishes new designations, and an address that screened clean last month can be designated today. Webhooks close that gap — when an address your key has previously screened appears in a newer SDN publication, ARGUS sends a sanctions.designation event to your configured endpoint.
{
"id": "evt_9f2c81d4",
"type": "sanctions.designation",
"createdAt": "2026-09-02T14:11:08Z",
"data": {
"address": "T111111111111111111111111111111111",
"network": "tron",
"firstScreenedAt": "2026-08-23T09:30:00Z",
"hit": {
"name": "EXAMPLE DESIGNATED ENTITY",
"uid": 99999,
"type": "Entity",
"asset": "TRX",
"programs": ["CYBER2"]
},
"listPublishDate": "09/01/2026"
}
}Deliveries are signed with an HMAC-SHA256 signature header so you can verify the payload came from us, and are retried with backoff for 24 hours until your endpoint returns a 2xx. The address and entity above are placeholders — the address cannot pass base58check and the entity does not exist.
Early access
Keys are not being issued yet. If you want to build against this API — or you can already see a problem with it — say so via the contact page under “API & partnerships”. Integrators who review the spec now get keys first, and changes made before launch cost nothing.