Skip to content
OfacScanner

API Documentation for Sanctions Screening

The OfacScanner API v1 is a JSON REST API that screens names, runs batches, adds records to monitoring and reports list versions. You authenticate with a Bearer key, retry safely with an Idempotency-Key and receive signed webhooks.

Engineer integrating screening into an onboarding flow at a standing desk

What the OfacScanner API does

The API lets your own systems run the same screening as the OfacScanner console. Call it when a user signs up, before a payout or a wire leaves, or when a shipment is booked. Every call is matched against the current version of each list in your plan, and the answer tells you which version was used so you can keep it as evidence.

All requests go to https://ofacscanner.com/api/v1 over HTTPS, take JSON bodies and return JSON. Times are ISO 8601 in UTC. Live keys work on the Scale and Enterprise plans, and sandbox keys work on every account. Read the overview of real time sanctions screening for integration patterns.

Authentication with Bearer keys

Create keys in the app under Developers. Send the key in the Authorization header as Bearer ofs_live_... for live calls or Bearer ofs_test_... for the sandbox. A key is shown once and stored only as a hash, so keep it in your secret store.

Sandbox keys return the same deterministic answer for the same input and never use checks. Live keys screen against real list data and count each screening as one check in your billing period.

Safe retries with Idempotency-Key

Add an Idempotency-Key header of up to 191 characters to any POST call. If a network error hides the answer, send the same request again with the same key. Within 24 hours you get the saved response with the header Idempotent-Replayed: true, and no second check is used.

The same key with a different body returns 422 idempotency_conflict, and a call still running under that key returns 409 idempotency_in_progress. A good key is your own customer or payment id plus the action, such as onboarding-cus-1042.

POST /api/v1/screen

Screen one name

Screens one person, company, vessel or aircraft against every list your plan covers and returns the risk rating, the top candidates and the list versions used. Add monitor true to keep watching the subject after this call.

Parameters for Screen one name
Field Description
namestring, required Full name, 2 to 500 characters. Any script works, transliteration is automatic.
typestring any, person, individual, organization, company, vessel or aircraft. Default any.
countrystring Country of residence, nationality or registration. Raises the score when it fits.
dobstring Date of birth such as 1971-04-12 or a year. Lowers the score when it does not fit.
referencestring Your own id for the customer or payment, returned in results and webhooks.
identifiersarray of strings Up to 10 identifiers such as passport, IMO or tax numbers.
sensitivitystring strict (95), balanced (85) or broad (75). Default is your workspace threshold.
monitorboolean Also add the subject to ongoing monitoring. Needs monitoring in your plan.

Request

curl https://ofacscanner.com/api/v1/screen \
  -H "Authorization: Bearer ofs_live_your_key" \
  -H "Idempotency-Key: onboarding-cus-1042" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Northwind Freight Ltd",
    "type": "organization",
    "country": "Panama",
    "reference": "cus_1042",
    "monitor": true
  }'

Response

{
  "object": "screening",
  "id": "scr_8Kf2xQ7wLm",
  "livemode": true,
  "channel": "api",
  "reference": "cus_1042",
  "query": { "name": "Northwind Freight Ltd", "type": "organization", "country": "Panama" },
  "result": "clear",
  "risk_rating": "clear",
  "top_score": 41.2,
  "threshold": 85,
  "sensitivity": "balanced",
  "matches_count": 0,
  "matches": [],
  "list_versions": [
    { "list": "ofac_sdn", "version_id": 1, "published_at": "2026-10-09T00:00:00+00:00" },
    { "list": "ofac_cons", "version_id": 2, "published_at": "2026-09-14T00:00:00+00:00" }
  ],
  "monitoring": { "record_id": 881, "status": "active" },
  "duration_ms": 84,
  "created_at": "2026-10-11T09:14:03+00:00"
}
GET /api/v1/screenings/{id}

Retrieve a screening

Returns a screening from your workspace by its id, with the same fields as the screen call. Use it to rebuild evidence or to show a past result in your own back office.

Parameters for Retrieve a screening
Field Description
idpath The id returned by POST /screen, a batch result or a webhook.

Request

curl https://ofacscanner.com/api/v1/screenings/scr_8Kf2xQ7wLm \
  -H "Authorization: Bearer ofs_live_your_key"

Response

{
  "object": "screening",
  "id": "scr_8Kf2xQ7wLm",
  "result": "clear",
  "risk_rating": "clear",
  "top_score": 41.2,
  "list_versions": [ ... ],
  "evidence_hash": "9f2c..."
}
POST /api/v1/batch

Screen a batch

Queues up to 10,000 records in one call and answers with 202 at once. Poll GET /batch/{id} or listen for the batch.completed webhook. Each record counts as one check. For larger files use CSV upload in the app, up to 100,000 rows per file.

Parameters for Screen a batch
Field Description
recordsarray, required 1 to 10,000 objects with the same fields as POST /screen.
monitorboolean Add every record to ongoing monitoring.
open_casesboolean Open a case for each possible match. Default true.
sensitivitystring strict, balanced or broad for the whole batch.

Request

curl https://ofacscanner.com/api/v1/batch \
  -H "Authorization: Bearer ofs_live_your_key" \
  -H "Idempotency-Key: payouts-2026-10-11" \
  -H "Content-Type: application/json" \
  -d '{
    "records": [
      { "name": "Maria Lopez", "type": "person", "dob": "1988", "reference": "sel_77" },
      { "name": "Example Vessel Star", "type": "vessel", "reference": "shp_3" }
    ],
    "monitor": true
  }'

Response

{
  "object": "batch",
  "id": 57,
  "status": "pending",
  "rows": 2,
  "processed": 0,
  "clear": 0,
  "review": 0,
  "match": 0,
  "skipped": 0,
  "livemode": true,
  "results_url": "https://ofacscanner.com/api/v1/batch/57"
}
POST /api/v1/monitor

Add a record to monitoring

Saves a subject for ongoing monitoring. After every list update OfacScanner re-screens it against the new entries and sends a monitoring.alert webhook when it now matches. Re-screening does not use your monthly checks.

Parameters for Add a record to monitoring
Field Description
name and the other fieldssame as POST /screen Send the same subject data you would screen.

Request

curl https://ofacscanner.com/api/v1/monitor \
  -H "Authorization: Bearer ofs_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Northwind Freight Ltd", "type": "organization", "reference": "cus_1042" }'

Response

{
  "object": "monitored_record",
  "id": 881,
  "livemode": true,
  "status": "active",
  "name": "Northwind Freight Ltd",
  "reference": "cus_1042",
  "last_result": "clear",
  "last_top_score": 41.2,
  "last_screening_id": "scr_8Kf2xQ7wLm",
  "created_at": "2026-10-11T09:14:03+00:00"
}
GET /api/v1/lists

List sources and versions

Returns every list with its issuing authority, official source, current version, publish date, the time of our last check and whether your plan includes it.

Request

curl https://ofacscanner.com/api/v1/lists \
  -H "Authorization: Bearer ofs_live_your_key"

Response

{
  "object": "list",
  "data": [
    {
      "list": "ofac_sdn",
      "name": "OFAC Specially Designated Nationals and Blocked Persons List",
      "authority": "Office of Foreign Assets Control, U.S. Department of the Treasury",
      "jurisdiction": "US",
      "source_url": "https://sanctionslist.ofac.treas.gov/",
      "included_in_plan": true,
      "version_id": 1,
      "published_at": "2026-10-09T00:00:00+00:00",
      "checked_at": "2026-10-11T09:01:32+00:00",
      "entries": 19416
    }
  ]
}

Errors and rate limits

Errors return a JSON body with a machine readable type and a human message, for example {"error": {"type": "plan_required", "message": "..."}}. Validation errors add a fields object.

API error codes
Status Type When it happens
400 invalid_request_error The Idempotency-Key is longer than 191 characters.
401 authentication_error The Bearer key is missing, malformed or revoked.
402 usage_limit_reached No checks left in this billing period. Checks reset with the next period or right after an upgrade.
403 plan_required A live key on a plan without the API, batch or monitoring feature.
404 not_found The id does not exist in your workspace.
409 idempotency_in_progress A request with the same Idempotency-Key is still running.
422 invalid_request_error or idempotency_conflict A field failed validation, or the Idempotency-Key was used with a different body.
429 rate limit More than 600 requests a minute on a live key, or 120 on a sandbox key.

Webhooks signed with HMAC

Add an endpoint URL in the app and choose its events: screening.completed, batch.completed, case.created and monitoring.alert. Webhooks are part of Growth and higher. Each delivery is a POST with a JSON event and the header OfacScanner-Signature: t=<unix time>,v1=<signature>.

The signature is HMAC SHA-256 of the timestamp, a dot and the raw body, keyed with the endpoint secret. Compute it yourself, compare in constant time and reject events older than 5 minutes. Answer with any 2xx status. Failed deliveries are retried, and the event id lets you ignore a repeat. See how alerts fit ongoing sanctions monitoring.

Event body

{
  "id": "evt_01JA9Q3Y7D2K8M4N6P0R2S4T6V",
  "type": "monitoring.alert",
  "created": "2026-10-11T09:31:12+00:00",
  "livemode": true,
  "data": {
    "object": "monitoring_alert",
    "id": 412,
    "reason": "new_match",
    "result": "likely",
    "top_score": 93.5,
    "record": { "id": 881, "name": "Northwind Freight Ltd", "reference": "cus_1042" },
    "screening_id": "scr_9Hd3kP2vQa",
    "case_id": 57,
    "list": "ofac_sdn",
    "list_version_id": 8,
    "list_published_at": "2026-10-11T00:00:00+00:00",
    "created_at": "2026-10-11T09:31:12+00:00"
  }
}

Verify the signature in Python

import hmac, hashlib, time

def verify(secret: str, raw_body: bytes, header: str) -> bool:
    parts = dict(p.split('=', 1) for p in header.split(','))
    t, sig = parts['t'], parts['v1']
    if abs(time.time() - int(t)) > 300:
        return False
    expected = hmac.new(secret.encode(), f'{t}.'.encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

API questions

Another question? Write to [email protected].

Which plan includes the API?

Live API keys work on Scale and Enterprise. Sandbox keys work on every account so your developers can build and test before you upgrade.

Does a sandbox call use my monthly checks?

No. Sandbox keys return deterministic answers for the same input and never count as usage. Only live calls that run a screening count as checks.

How fast is a screening call?

Real time screening on Scale answers in under 300 ms. Each response includes duration_ms so you can track it in your own monitoring.

Can I retry a request safely?

Yes. Send the same Idempotency-Key with the same body and you get the saved response back without a second check. Keys are kept for 24 hours.

How do I know which list version a result used?

Every screening response has a list_versions array with the list code, the version id and the publish date. Store it with your decision as part of your evidence.

Test the API with a sandbox key

Create an account, add a sandbox key under Developers and send your first request. Move to Scale when you are ready for live screening.

Results support your compliance decisions, and the final decision stays with your team. OfacScanner is not affiliated with OFAC or the U.S. Department of the Treasury.