API
API documentation
Integrate sanctions screening directly into your applications with our REST API.
Getting started
The OFACScreen API allows you to programmatically screen names and entities against OFAC and other sanctions lists. Follow these steps to get up and running:
Create an account
Create an account. The REST API is on every plan, including the 14-day trial, so you can integrate before you pay.
Generate API key
Create a key under API keys in your dashboard.
Make your first call
Use the examples below to start screening against sanctions lists.
Authentication
All API requests must include a Bearer token in the Authorization header. You can generate API keys from your account dashboard.
Authorization: Bearer your_api_key_here
Keep your API key secret. Do not expose it in client-side code, public repositories, or browser requests.
Screen (Single)
/api/v1/screen/
Screen one name against the default lists, the ones Lists marks "core": true. The name can also be a wallet address, ID number, email, website or phone number, which is matched against the ones the lists record. Returns match results with confidence scores.
Send the party's email, phone or website beside its name to check those too. A field can hold up to 5 values separated by commas, semicolons or line breaks. The name counts as one search, and each email, phone number or website one more. matches stays the name's. A listed party recorded with one of your values comes back in contact_matches, shaped like matches, with a score of 1.0 and matched_alias naming what it matched, such as "Email Address [email protected]". A website or email on the domain of a listed website scores 0.9, as does a phone number that matches without its country code. contacts lists each value you sent with its total_matches, or an error when it is not a valid email address, phone number or website or is past the fifth value of its field, in which case it is not searched or charged.
Request
curl -X POST https://api.ofacscreen.com/api/v1/screen/ \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "John Smith",
"email": "[email protected]",
"threshold": 0.3
}'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Name, wallet address, ID number, email, website or phone number to screen (max 500 characters) |
email |
string | No | The party's email address, checked against the email addresses the lists record. One more search. |
phone |
string | No | The party's phone number with its area code, checked against the phone numbers the lists record. One more search. |
website |
string | No | The party's website or domain, checked against the websites and email domains the lists record. One more search. |
type |
string | No | "individual", "entity", "vessel", or "aircraft". Defaults to all types. Leave it out when screening people: some lists record people as entities. |
country |
string | No | The country the party is in. Any spelling or ISO code. An embargoed or high-risk country comes back in jurisdiction_flags; see Jurisdiction flags. |
threshold |
number | No | Minimum match score between 0.0 and 1.0. Defaults to 0.3. |
lists |
array | No | List codes from Lists to search instead of the default ones. Omit it to search every list marked "core": true; a list marked false is searched only when named. An unknown code is refused with a 400. The response's lists_searched names the lists screened. |
limit |
integer | No | Return only the highest-scoring limit matches. Omit it and every match is returned, which is the default. total_matches is always the real total, so total_matches greater than the length of matches means the rest were above your limit, not missing. |
Response
{
"query": "John Smith",
"screened_at": "2026-03-04T14:30:00Z",
"lists_searched": ["AU_DFAT", "BIS_DPL", "OFAC_NONSDN", "OFAC_SDN", "..."],
"total_matches": 1,
"contacts": [{"type": "email", "value": "[email protected]", "total_matches": 0}],
"total_contact_matches": 0,
"contact_matches": [],
"matches": [
{
"id": 281578,
"name": "John Ka-chiu LEE",
"entry_type": "individual",
"list_code": "OFAC_SDN",
"list_name": "OFAC Specially Designated Nationals (SDN)",
"program": "HK-EO13936",
"remarks": "",
"score": 0.333,
"score_pct": 33,
"matched_alias": "John LEE",
"aliases": ["John LEE", "Ka Chiu LEE"],
"addresses": [{"city": "Kowloon", "country": "Hong Kong"}],
"identifications": [{"type": "National ID No.", "number": "G0286787"}],
"match_level": "low"
}
],
"jurisdiction_flags": []
}
Screen (Batch)
/api/v1/screen/batch/
Screen multiple names or entities in a single request. Supports up to 100 names per batch on every plan. For larger batches, use the CSV upload feature in the web dashboard, where the per-file row limit rises with your plan.
Send names to screen names alone, or items to screen each name with its street address, country, email, phone and website. Each name counts as one search, each email, phone number or website one more, and each address one more when it names a street or building, as on Screen (Address). An address naming only a city or a country comes back with an address_error and is neither searched nor charged. The quota check covers the whole request before anything runs.
Request
curl -X POST https://api.ofacscreen.com/api/v1/screen/batch/ \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"items": [
{"name": "Acme Trading LLC", "address": "Tverskaya Street 7, Moscow 125009", "country": "Russia"},
{"name": "Jane Doe", "address": "Moscow", "country": "Russia", "email": "[email protected]"},
{"name": "John Smith"}
],
"threshold": 0.3
}'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
names |
array | This or items |
Array of name strings to screen (max 100) |
items |
array | This or names |
Array of objects to screen (max 100), each with a name (required, max 500 characters), an address (optional, max 500), a country (optional, max 100), and an email, phone and website (optional, max 500 each, as on Screen (Single)). An item's country narrows its searches to listed entries tied to that country or to none, as on Screen (Single), and with its address is read for its jurisdiction_flags. |
type |
string | No | "individual", "entity", "vessel", or "aircraft". Defaults to all types. Leave it out when screening people: some lists record people as entities. |
threshold |
number | No | Minimum match score between 0.0 and 1.0. Defaults to 0.3. |
lists |
array | No | List codes from Lists to search instead of the default ones. Omit it to search every list marked "core": true; a list marked false is searched only when named. An unknown code is refused with a 400. The response's lists_searched names the lists screened. |
Response
{
"screened_at": "2026-03-04T14:30:00Z",
"lists_searched": ["AU_DFAT", "BIS_DPL", "OFAC_NONSDN", "OFAC_SDN", "..."],
"total_screened": 5,
"results": [
{
"query": "Acme Trading LLC",
"total_matches": 0,
"matches": [],
"address": "Tverskaya Street 7, Moscow 125009",
"total_address_matches": 1,
"address_matches": [{"name": "TVERSKAYA TRADING LLC", "matched_address": {...}, "...": "..."}],
"jurisdiction_flags": [{"tier": "high_risk", "jurisdiction": "Russia", "...": "..."}]
},
{
"query": "Jane Doe",
"total_matches": 0,
"matches": [],
"address": "Moscow",
"address_error": "Enter a street address: ...",
"contacts": [{"type": "email", "value": "[email protected]", "total_matches": 0}],
"total_contact_matches": 0,
"contact_matches": [],
"jurisdiction_flags": [{"tier": "high_risk", "jurisdiction": "Russia", "...": "..."}]
},
{
"query": "John Smith",
"total_matches": 1,
"matches": [...],
"jurisdiction_flags": []
}
]
}
matches are always the name's. An item sent with an email, phone or website adds contact_matches and contacts, as on Screen (Single). An item sent with an address adds address_matches, shaped as on Screen (Address) with each match's matched_address, or address_error saying why it was not searched. total_screened is the number of searches that ran and were charged. A search that failed comes back as an error (or address_error) and is not charged; retry it rather than reading it as no match.
Screen (Address)
/api/v1/screen/address/
Screen one street address against the addresses the sanctions lists record. Returns the listed parties whose address resembles it, in the same shape as a name screening, each with the matched_address it matched on. The score is how alike the two addresses are, with street types read alike ("ul." and "Street"), plus 0.1 when the listed postal code is in your address. A listed address must also share a word of its street with yours, so a city alone never matches. Each request counts as one search. The lists record addresses for only some of the parties on them, so no match clears no one at the address: screen the names too.
Request
curl -X POST https://api.ofacscreen.com/api/v1/screen/address/ \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"address": "Tverskaya Street 7, Moscow 125009",
"country": "Russia"
}'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
address |
string | Yes | The street address to screen, as fully as you have it: street and number or building, city, postal code (max 500 characters). It must name a street or a building; a city or country on its own is refused with a 400 and not charged. |
country |
string | No | Keep only listed addresses in this country, and those with no country on file. Any spelling or ISO code. Read with the address for jurisdiction_flags. |
threshold |
number | No | Minimum match score between 0.0 and 1.0. Defaults to 0.3. |
lists |
array | No | As for Screen (Single). |
limit |
integer | No | As for Screen (Single). |
Response
{
"query": "Tverskaya Street 7, Moscow 125009",
"screened_at": "2026-03-04T14:30:00Z",
"lists_searched": ["AU_DFAT", "BIS_DPL", "OFAC_NONSDN", "OFAC_SDN", "..."],
"total_matches": 1,
"matches": [
{
"name": "TVERSKAYA TRADING LLC",
"list_code": "OFAC_SDN",
"score": 1.0,
"match_level": "high",
"matched_address": {
"address": "ul. Tverskaya, d. 7",
"city": "Moscow",
"state": "",
"postal_code": "125009",
"country": "Russia"
},
"...": "the other fields of a name match"
}
],
"jurisdiction_flags": [
{
"tier": "high_risk",
"jurisdiction": "Russia",
"evidence": "country \"Russia\"",
"...": "see Jurisdiction flags"
}
]
}
Jurisdiction flags
Both single endpoints, and each result of Screen (Batch), return jurisdiction_flags: the embargoed and high-risk places the request points to. Screen (Single) reads the country you send; Screen (Address) reads the address too, including its postal code and the region or town it names. It is an empty array when nothing points anywhere flagged.
A flag is based on the address or country. It is not a sanctions match: it never adds to matches or total_matches, never changes whether the request found a match, and is not counted as one in your audit trail. An empty matches with an embargoed flag is not a clearance.
Fields of each flag
| Field | Description |
|---|---|
tier |
embargoed: US comprehensive sanctions, under which nearly every dealing needs an OFAC licence. high_risk: broad or sectoral US sanctions, a FATF call for action or a FinCEN special measure, short of an embargo. Flags come strongest first, one per place. |
jurisdiction |
The country or region, as a name to show. |
reason |
Why it is flagged, in plain words. For the Donetsk and Luhansk regions it says the embargo covers only the part held by the so-called People's Republics, so check which side of the line of contact the address is on. |
authority, source_url |
The program or body behind the reason, and where it is published. |
evidence |
What in your request raised it: the country, a region name, a postal code or a place name. |
other_grounds |
Weaker reasons for the same place, each with tier, reason, authority and source_url. |
Example
POST /api/v1/screen/address/
{"address": "ul. Lenina 10, Simferopol 95000, Ukraine"}
{
"query": "ul. Lenina 10, Simferopol 95000, Ukraine",
"total_matches": 0,
"matches": [],
"jurisdiction_flags": [
{
"tier": "embargoed",
"jurisdiction": "Crimea region of Ukraine",
"reason": "US embargo: nearly all dealings with the Crimea region, Sevastopol included, are prohibited without an OFAC licence.",
"authority": "OFAC, Executive Order 13685",
"source_url": "https://ofac.treasury.gov/sanctions-programs-and-country-information/ukraine-russia-related-sanctions",
"evidence": "postal code 95000, place name \"Simferopol 95000\" (Simferopol)",
"other_grounds": []
}
],
"...": "lists_searched and screened_at as above"
}
Lists
/api/v1/lists/
Retrieve information about all available sanctions lists. last_updated is when we last fetched the list; data_as_of is the date its publisher put on that copy, or null where the publisher gives none. core says whether a screening searches the list when it names no lists. entry_count is the number of entries on the list. This endpoint does not require authentication.
Request
curl https://api.ofacscreen.com/api/v1/lists/
Response
{
"lists": [
{
"code": "OFAC_SDN",
"name": "OFAC Specially Designated Nationals (SDN)",
"description": "The primary US sanctions list maintained by the Office of Foreign Assets Control.",
"country": "United States",
"last_updated": "2026-03-04T12:00:00Z",
"data_as_of": null,
"core": true,
"entry_count": 18452
},
{
"code": "EU_FSF",
"name": "EU Financial Sanctions (FSF)",
"description": "The European Union consolidated list of persons, groups and entities subject to EU financial sanctions.",
"country": "European Union",
"last_updated": "2026-03-04T11:00:00Z",
"data_as_of": "2026-02-27",
"core": true,
"entry_count": 5870
}
]
}
Monitoring
/api/v1/monitoring/
Manage the names and street addresses you monitor. Each is automatically re-screened on every sanctions list update, a name against the listed names and an address against the addresses the lists record. You'll receive an email alert when a new match is detected.
List entities
curl https://api.ofacscreen.com/api/v1/monitoring/ \
-H "Authorization: Bearer your_api_key_here"
{
"entities": [
{
"id": 42,
"kind": "name",
"name": "John Smith",
"entity_type": "individual",
"last_checked_at": "2026-03-04T12:00:00Z",
"last_match_found": false,
"last_match_score": 0.0
},
{
"id": 43,
"kind": "address",
"name": "Tverskaya Street 7, Moscow",
"country": "Russia",
"entity_type": null,
"last_checked_at": "2026-03-04T12:00:00Z",
"last_match_found": true,
"last_match_score": 92.0
}
],
"total": 2
}
kind is name or address. The watched text is in name either way; an address also has the country it was added with (empty for none) and no entity type.
Add entity
curl -X POST https://api.ofacscreen.com/api/v1/monitoring/ \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "John Smith", "entity_type": "individual"}'
{
"id": 42,
"kind": "name",
"name": "John Smith",
"entity_type": "individual",
"created": true
}
Add address
curl -X POST https://api.ofacscreen.com/api/v1/monitoring/ \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"address": "Tverskaya Street 7, Moscow", "country": "Russia"}'
{
"id": 43,
"kind": "address",
"name": "Tverskaya Street 7, Moscow",
"country": "Russia",
"entity_type": null,
"created": true
}
Send address instead of name to watch a street address. It must name a street or building: a city or country alone is refused with a 400 and not added. The optional country keeps matches tied to that country or to none, as it does for /api/v1/screen/address/. An alert is sent when a listed party's recorded address starts matching. Jurisdiction flags for the address show on the monitoring page but never raise an alert.
Remove entity
curl -X DELETE https://api.ofacscreen.com/api/v1/monitoring/ \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"id": 42}'
{"id": 42, "deleted": true}
Note: The number of monitored names and addresses is limited by your plan, each address counting as one, like a name. Entities are automatically screened on every sanctions list update. Email alerts are sent when a new match is detected.
Rate limits
API calls draw on the same monthly search allowance as the web interface, so one quota covers both. Rate limit headers are included in every response.
| Plan | Monthly quota |
|---|---|
| Free Trial | 25 searches |
| Starter | 1,000 searches |
| Professional | 2,000 searches |
| Business | 10,000 searches |
| Enterprise | Unlimited |
Rate limit headers
X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 9955
If you exceed your monthly quota, you will receive a 429 Too Many Requests response. On a paid plan the allowance resets on the 1st of the month: resets_at gives the time, and the Retry-After header the seconds until then, at most 86400 (one day). A trial's searches do not reset, so its 429 has no Retry-After.
Error codes
The API uses standard HTTP status codes to indicate success or failure.
| Status | Description |
|---|---|
200 |
Success. Results returned. |
400 |
Bad request. Check your request parameters. |
401 |
Unauthorized. Invalid or missing API key. |
403 |
Forbidden. The trial or plan has ended, or the plan has no API access. See reason below. |
429 |
The plan's or the trial's searches are used up, or too few remain for the batch. On a paid plan, retry after Retry-After seconds. |
500 |
Internal server error. Contact support if this persists. |
Error response format
{
"error": "name field is required"
}
403 and 429 fields
| Field | Status | Description |
|---|---|---|
reason |
403, 429 | "trial_ended", "plan_ended", "quota_exhausted", "not_included" or "no_plan". |
upgrade_url |
403, 429 | On a trial or with no plan, checkout for Starter, billed monthly. On a paid plan, the plans page. |
pricing_url |
403, 429 | The plans page. |
limit, used, remaining |
429 | The month's allowance and what is left of it. |
required |
429 | The searches this request needed. A batch counts each name, and each street address, as one. |
resets_at |
429 | When the allowance resets, in ISO 8601. null on a trial. |
HTTP/1.1 429 Too Many Requests
Retry-After: 86400
{
"error": "Monthly search limit exceeded",
"limit": 10000,
"used": 9990,
"remaining": 10,
"required": 40,
"resets_at": "2026-11-01T00:00:00-04:00",
"reason": "quota_exhausted",
"upgrade_url": "https://www.ofacscreen.com/pricing/#plans",
"pricing_url": "https://www.ofacscreen.com/pricing/"
}
MCP server for AI agents
An AI agent or assistant that supports remote MCP servers can screen through this URL. It is free, needs no API key and allows up to 25 screenings a day. An agent that calls the REST API instead can read the OpenAPI document. Setup for Claude, ChatGPT and other clients is on the MCP server page.
https://www.ofacscreen.com/mcp
Tools
| Tool | Description |
|---|---|
screen_entity |
Screen a person or company name, with its email, phone or website if you have them. |
screen_address |
Screen a street address. |
list_sanctions_sources |
The lists, with each one's code, last update and entry count. |
search, fetch |
Find listed entries by name and read one entry, for ChatGPT deep research and company knowledge. |
API
Ready to integrate?
The REST API is on every plan, including the 14-day trial. Start the trial and create your API key.