Skip to content
← ARGUSProduct

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.

Specification — not yet live

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.

Base URL
https://api.argus.example
Request headers
Authorization: Bearer <your key>
Accept: application/json

Keys 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

GET/v1/screen/{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.

Request — curl
curl https://api.argus.example/v1/screen/TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t \
  -H "Authorization: Bearer $ARGUS_API_KEY"
Request — TypeScript
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.
}
Response shape
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;
}
Response — 200
{
  "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

POST/v1/screen/batch

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.

Request — curl
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"
    ]
  }'
Response — 200
{
  "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 body
{
  "error": {
    "code": "invalid_address",
    "message": "TRON address failed base58check — likely a typo."
  }
}
400invalid_address

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.

400invalid_request

The body is not valid JSON, addresses is empty, or a batch exceeds 100 entries.

401unauthorized

The API key is missing, malformed, or revoked.

404not_found

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.

429rate_limited

Over the per-key limit. The Retry-After header says when to try again.

5xxupstream_unavailable

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.

Sustained rate10 requests / second per key
Burst50 requests
Batch size100 addresses per request
Metering1 call per address screened
Price$0.04 per call · volume pricing from 50,000 calls

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.

Webhook payload
{
  "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.