SAM.gov Exclusions & OFAC Screening
Screen a vendor company against SAM.gov Exclusions and the OFAC/BIS Consolidated Screening List in one call — the check a procurement team runs before onboarding a new vendor.
Not open for signups yet. It opens once its daily SAM.gov refresh has run cleanly on its own for several consecutive days and a final audit passes. Questions in the meantime: aerviklabs@gmail.com.
The problem
A vendor can be added to SAM.gov Exclusions or to a federal sanctions list after it was approved, so a screen run at onboarding says nothing about later. Both are free to search by hand: SAM.gov's exclusions search needs no login, and trade.gov's Consolidated Screening List search covers the Treasury, Commerce and State Department lists in one search. That is still two searches per vendor, and running them from code means two integrations and, on SAM.gov's per-query API, a daily request limit.
Who it's for
Procurement, vendor-management, and compliance teams that need to screen a company or vendor entity — not a specific shipment — before onboarding a new vendor and on an ongoing basis afterward.
Use cases
- Vendor onboarding screen before signing a new supplier or contractor
- Periodic re-screening of an existing vendor or supplier roster
- Batch screening ahead of a procurement or vendor-risk audit
- Screening a business partner or reseller before signing a contract
What it does
Send a company or vendor entity name and get back potential matches from SAM.gov Entity Exclusions and the Consolidated Screening List (CSL), which itself covers OFAC's Specially Designated Nationals (SDN) list, the Commerce Department's BIS Entity List, and several other federal denied/restricted-party lists. An optional two-letter state is compared with each SAM.gov match's state; an optional address, UEI or D-U-N-S Number is echoed back for your own reference. A batch endpoint screens up to 25 vendor entities in one call. Every section of every response carries a source manifest showing whether it came from live government data and, where the source gives one, the source's own date for that data.
Why Aervik's implementation is different
Every hit is reported as a potential match requiring human verification — never asserted as a confirmed exclusion or sanctions determination. Each section carries source.basis and source.as_of, and overall.incomplete_coverage is true when a section is not live, could not be checked, reached a scan or page limit, or held back near misses (records scored under the match floor; on SAM.gov, those scoring 0.5 or more). While it is true, overall.status cannot read no_potential_matches_found. The subject of every screen is a company or vendor entity — a different question from Aervik Labs' US Import Risk Screening API, where the subject is a specific shipment or supplier-of-record.
Example
Request
POST /screen
{ "entity_name": "0DAY TECHNOLOGIES" }
Response
Captured live 2026-09-15 at $0, abridged: 2 of the 15 SAM.gov matches, with the reasons list and each source’s name and url omitted for length. Values verbatim. SAM.gov and the CSL are read live, so counts move between calls.
{
"input": {
"entity_name": "0DAY TECHNOLOGIES"
},
"coverage": "Entity records only. Records SAM.gov classifies as individuals are excluded from this service. Screen individuals at SAM.gov directly.",
"sam_gov_exclusions": {
"status": "match",
"matches": [
{
"matched_name": "0DAY TECHNOLOGIES",
"match_type": "exact",
"score": 1,
"open_data_flag": null,
"source_record_count": 1,
"state_check": "not_applicable",
"reason": "Potential match on SAM.gov Exclusions: \"0DAY TECHNOLOGIES\" closely resembles listed business \"0DAY TECHNOLOGIES\" (exact match, score 1). This is a potential match requiring human verification, not a confirmed exclusion determination.",
"subject_type": "business",
"exclusion_type": "Prohibition/Restriction — Reciprocal — OFAC",
"exclusion_date": "2023-02-24",
"reinstated_date": null,
"state": null,
"address": "UL. PROFSOYUZNAYA D. 125, MOSCOW, 117647"
},
{
"matched_name": "LUZY TECHNOLOGIES LLC",
"match_type": "fuzzy",
"score": 0.824,
"open_data_flag": null,
"source_record_count": 1,
"state_check": "not_applicable",
"reason": "Potential match on SAM.gov Exclusions: \"0DAY TECHNOLOGIES\" closely resembles listed business \"LUZY TECHNOLOGIES LLC\" (fuzzy match, score 0.824). This is a potential match requiring human verification, not a confirmed exclusion determination.",
"subject_type": "business",
"exclusion_type": "Prohibition/Restriction — Reciprocal — OFAC",
"exclusion_date": "2020-06-18",
"reinstated_date": null,
"state": null,
"address": "778 BOYLSTON STREET, UNIT 6B, BOSTON, 02199"
}
],
"source": {
"basis": "live",
"as_of": "2026-09-14"
},
"candidate_scan_truncated": false,
"records_below_match_threshold": 76
},
"csl": {
"status": "match",
"matches": [
{
"matched_name": "0DAY TECHNOLOGIES",
"match_type": "exact",
"score": 1,
"subject_type": "entity",
"reason": "Potential match on the Consolidated Screening List: \"0DAY TECHNOLOGIES\" closely resembles listed entity \"0DAY TECHNOLOGIES\" on Specially Designated Nationals (SDN) - Treasury Department (exact match, score 1). This is a potential match requiring human verification, not a confirmed denied-party or sanctions determination.",
"aliases": [
"LLC ZIROUDEY TEKHNOLODZHIS",
"LIMITED 0DAY TECHNOLOGIES",
"LTD 0DT"
],
"source_list": "Specially Designated Nationals (SDN) - Treasury Department"
},
{
"matched_name": "IRAY TECHNOLOGIES",
"match_type": "fuzzy",
"score": 0.882,
"subject_type": "entity",
"reason": "Potential match on the Consolidated Screening List: \"0DAY TECHNOLOGIES\" closely resembles listed entity \"IRAY TECHNOLOGIES\" on Specially Designated Nationals (SDN) - Treasury Department (fuzzy match, score 0.882). This is a potential match requiring human verification, not a confirmed denied-party or sanctions determination.",
"aliases": [
"IRAY TECHNOLOGY CO LTD",
"IRAY TECHNOLOGIES",
"YANTAI AIRUI OPTOELECTRONIC TECHNOLOGY CO LTD"
],
"source_list": "Specially Designated Nationals (SDN) - Treasury Department"
}
],
"source": {
"basis": "live",
"as_of": null,
"note": "Fetched live from data.trade.gov for this request. The CSL search response carries no per-list update date (response keys verified 2026-09-11), so as_of is null rather than our own clock. We queried it 2026-09-15 (UTC)."
},
"result_page_truncated": false,
"total_upstream_results": 3,
"records_below_match_threshold": 1
},
"overall": {
"status": "potential_matches_found",
"total_matches": 17,
"reasons": [
"... one sentence per match and one per held-back count, omitted here for length ..."
],
"incomplete_coverage": true
}
}
What a call looks like. These are the real request and response shapes, but this API is not accepting new signups right now — a new key cannot be issued for it, so these will not run for you today.
cURL
curl -X POST "https://business-entity-sam-gov-ofac-csl-vendor-risk-screening-api.p.rapidapi.com/screen" \
-H "content-type: application/json" \
-H "X-RapidAPI-Key: $RAPIDAPI_KEY" \
-H "X-RapidAPI-Host: business-entity-sam-gov-ofac-csl-vendor-risk-screening-api.p.rapidapi.com" \
-d '{"entity_name": "Bank Melli", "state": "NY"}'
Python
import os
import requests
RAPIDAPI_HOST = "business-entity-sam-gov-ofac-csl-vendor-risk-screening-api.p.rapidapi.com"
resp = requests.post(
f"https://{RAPIDAPI_HOST}/screen",
json={"entity_name": "Bank Melli", "state": "NY"},
headers={
"X-RapidAPI-Key": os.environ["RAPIDAPI_KEY"],
"X-RapidAPI-Host": RAPIDAPI_HOST,
},
)
print(resp.json())
Node.js
const RAPIDAPI_HOST = 'business-entity-sam-gov-ofac-csl-vendor-risk-screening-api.p.rapidapi.com';
const res = await fetch(`https://${RAPIDAPI_HOST}/screen`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'X-RapidAPI-Key': process.env.RAPIDAPI_KEY,
'X-RapidAPI-Host': RAPIDAPI_HOST,
},
body: JSON.stringify({ entity_name: 'Bank Melli', state: 'NY' }),
});
console.log(await res.json());
Key features
- One call covers SAM.gov Entity Exclusions and the Consolidated Screening List (OFAC SDN, the BIS Entity List, and several other federal denied/restricted-party lists)
- Batch endpoint for roster-style screening, up to 25 vendor entities per call
- Every match includes a plain-language reason, never a bare score
- A source manifest on every section: SAM.gov's own extract date as as_of, and null on the CSL section, whose search response carries no date
Pricing
Pricing is published with the listing when it opens, including a free tier.
Frequently asked questions
What government sources does this API check?
One call to POST /screen checks SAM.gov Entity Exclusions and the Consolidated Screening List (CSL), which itself covers OFAC's Specially Designated Nationals (SDN) list, the Commerce Department's BIS Entity List, and several other federal denied/restricted-party lists. The two overlap: SAM.gov's extract carries reciprocal records for some OFAC listings, so one firm can match in both sections, as in the example above. GET /sources returns each section's source manifest without running a screen.
Can I use this to screen an individual person?
No — this is not a background-check or consumer-reporting product, and it must not be used for employment, tenancy, credit, or any other decision about a person. The subject of every screen is a company or vendor entity name. On the SAM.gov section a record is excluded when SAM.gov classifies it as an individual, which is most records on its Exclusions list (including debarred sole proprietors), or when its name reads as a person's, whatever label SAM.gov gives it; a name carrying a company legal form is not read that way, but some records about real firms are still excluded. On the CSL section a record the list types as an individual is excluded, and one it types as an entity, vessel or aircraft is screened; a record with no type is excluded when its name reads as a person's, or when it sits on a list of persons without a company legal form in its name. The scope is stated the same way on every response, in a constant coverage line: "Entity records only. Records SAM.gov classifies as individuals are excluded from this service. Screen individuals at SAM.gov directly." There is no per-query note saying a person-record sat behind a name you searched — that note would itself be information about that person. There is no option to include individuals; the exclusion is permanent, not a setting.
Does a 'no potential matches found' result mean the vendor is cleared?
No. This API is advisory only. Every match is reported as a potential match requiring independent human verification, never a confirmed exclusion or sanctions determination, and a "no potential matches found" result is never a certified clearance.
What does a screen not check?
The two sources above are the whole screen. It does not check GSA schedule or contracting status, state-level vendor debarment lists, or any other list outside those two sources. FASCSA orders are not read as a source of their own, and whether SAM.gov's Exclusions extract carries them has not been established; check SAM.gov for them directly. It cannot see ownership: a parent, subsidiary or affiliate of a listed party is reported only when its own name scores as a match.
What do the optional address, state, UEI, and D-U-N-S Number fields do?
state, when supplied, is compared as text with each SAM.gov Exclusions match's state field and reported as state_check: corroborated, conflict or not_applicable. It never removes or adds a match, and Consolidated Screening List matches carry no state_check. Records outside the US often carry no state (not_applicable), and some carry a city or province instead — one record in the example's capture has state "SHENZHEN" — which reads as conflict against any US state you send, so treat conflict on a non-US record as a text mismatch rather than as a different firm. address, uei, and duns are echoed back for your own reference only and are not used to filter or confirm a match.
Can I screen more than one vendor at a time?
Yes. POST /screen/batch screens up to 25 vendor entities in a single call, one after another. Each entity's two sections run in parallel and each is stopped after 20 seconds, so size your client timeout for up to 20 seconds per entity. A full batch of 25 took about 14 seconds, measured twice on 2026-09-15; two full batches sent at the same moment took about 26 seconds each, and one entity's sanctions-list section in them was still rate-limited after its retry. When the sanctions list rate-limits a request, it is retried once after a wait of up to 8 seconds; if a section still cannot be checked, that entity's section reports status "error" and overall.incomplete_coverage is true. One invalid entity rejects the whole batch with a 400 before any entity is screened.
Does this monitor my vendors and alert me when something changes?
No. This is an on-demand check: every call screens the entity you name, at the moment you ask. We do not store a vendor roster, watch it on a timer, or send alerts. Re-screening on a schedule is something your system does by calling this API again.
Is this a certified vendor risk determination or legal compliance guarantee?
No. Every match is reported as a "potential match requiring human verification," never asserted as fact, and this API is not a substitute for your organization's own vendor risk or compliance program. See GET /terms for the full disclosure and disclaimer.
What must I do if a party matches the Consolidated Screening List?
The International Trade Administration, which publishes the list, asks every service built on it to tell users: If a party to a user’s transaction matches the name of a party on the consolidated list, the user must check the official publication of restricted parties in the Federal Register or the official lists of restricted parties maintained on the websites of the Departments of Commerce, State and the Treasury to ensure full compliance with all of the terms and conditions of the restrictions placed on the parties on this list.
This is an on-demand check, not a monitoring subscription. Every call screens the entity you name, at the moment you ask. We don’t hold a vendor roster, watch it on a timer, or send you an alert when something changes — your system decides when to re-screen and owns the schedule. That’s a deliberate boundary, not a gap: a monitoring service that quietly misses a new listing is worse than no monitoring at all, and we would rather you keep the calendar than assume we have it.
Coverage today: both sections are live against real government data. The Consolidated Screening List (CSL) section calls trade.gov for each request whose name it can compare.
The SAM.gov Entity Exclusions section works differently. It is answered from our own copy of SAM.gov’s daily Exclusions extract, not from SAM.gov’s per-query Exclusions API, so no screen spends a SAM.gov request. That per-query API allowed our non-federal key 10 requests a day (confirmed by an HTTP 429 on 2026-08-27); SAM.gov documents a higher daily limit for keys with a SAM.gov role or a system account.
The copy is replaced by a scheduled job once a day at 13:00 UTC, after 7 AM Eastern, the time GSA gives for checking for the day’s file. A request never triggers a refresh. The job refuses an extract with no data rows, with fewer than half the rows of the copy being served, with a required column missing, or dated earlier than the copy being served, and does not start while another refresh is running; in each case the served copy and its date stay in place.
Read source.as_of on the SAM.gov section: it is SAM.gov’s own date for the extract, not the
day we fetched it. When that date is more than seven days old, the section’s source.note
says the data is stale and gives its age. Within a screening response the note is the only place
this is said: a stale copy does not change status, overall.status or
overall.incomplete_coverage, so if your process needs current data, compare source.as_of
with today’s date yourself. If SAM.gov’s date could not be read, as_of is not SAM.gov’s date,
and note says so and says how current the data is cannot be verified. If no copy has been loaded at all, the section reports
status: "error", not a clean result.
On the CSL section as_of is always null: trade.gov’s search response carries no per-list
update date, and this API does not read the per-list dates trade.gov publishes on a separate
endpoint. A null there means the response does not state how current the lists are; it does
not set overall.incomplete_coverage.
GET /sources returns each section’s source manifest without running a screen. GET /health
reports SAM.gov’s extract date (source_extract_date), its age in days, whether it is stale,
the row count of the served copy and the outcome of recent refresh runs. It does not judge
whether that row count is plausible.
Reading a response
overall.status is one of four values:
screening_incomplete: neither section could be checked (both reportstatus: "error"). You do not have a result; treat the vendor as unscreened and retry.potential_matches_found: at least one section returned a match.overall.incomplete_coveragecan still betrue, as it is in the example.no_matches_among_screened_records: nothing matched andoverall.incomplete_coverageistrue. Not a clean screen;overall.reasonssays what was not covered.no_potential_matches_found: nothing matched andoverall.incomplete_coverageisfalse. The strongest clean answer this API gives, and still not a clearance.
overall.incomplete_coverage is true when any of these happened, and each adds a sentence to
overall.reasons: a section’s source.basis is not live; a section reports status: "error",
including a name with no Latin letters or digits to compare; the SAM.gov scan reached its limit
of 500 candidate records (candidate_scan_truncated); trade.gov returned only part of its
results or reported no total (result_page_truncated); or a section held back records it scored
under the match floor (records_below_match_threshold above 0; the CSL section counts every
record trade.gov returned under the floor, the SAM.gov section only those scoring 0.5 or more).
The example is a response captured 2026-09-15, abridged: it shows 2 of the 15 SAM.gov matches
and both CSL matches, and leaves out the reasons, the disclaimer and most of each source. It was
captured before the two SAM.gov match fields described next existed, so they are not shown in it.
Dun & Bradstreet data on SAM.gov matches
SAM.gov’s Terms of Use treat exclusion records created before April 4, 2022 as records that may contain Dun & Bradstreet (D&B) data, and name the Legal Business Name and address fields as D&B Open Data, which may be used only with written attribution to D&B and never in bulk. Each SAM.gov match says which side of that line its record is on:
record_created_date: the created date SAM.gov’s extract gives the record, as published, ornull. It is notexclusion_date, which is when the exclusion took effect.dnb_open_data:"applies"when that date is before 2022-04-04,"does_not_apply"when it is on or after 2022-04-04, and"unknown"when it is missing or unreadable, which is handled the same as"applies".
Where dnb_open_data is "applies" or "unknown", that match’s matched_name (also quoted in
reason), address and state are the D&B Open Data fields, and the SAM.gov section’s
source.note carries the attribution to Dun & Bradstreet. That is SAM.gov’s rule for the record, not
a statement that D&B supplied those values. open_data_flag is returned as SAM.gov publishes it;
SAM.gov leaves it blank, so it says nothing about D&B. This API returns individual match results only.
How matching works
score runs from 0 to 1. Both names are lowercased and stripped of punctuation and common legal
forms (Inc., LLC, Co., Ltd., Corp., PLC and similar), and the score is the highest of three
comparisons: how close the whole names are by edit distance, how many of their words they share,
and 0.91 when the query has two or more words and all of them appear in the listed name. Records
scoring under 0.72 are not shown. match_type is exact at a score of 1 and fuzzy from 0.72 up
to 1. A section’s status is match when its best match scores 0.92 or more, and
possible_match from 0.72.
exact does not mean identical. It means the words matched after that normalization, in any
order. On the SAM.gov section, single letters present in only one of the two names are ignored,
which is how a search for “Technology” was reported as an exact match on a listed
“N.A.Z. TECHNOLOGY” (seen live 2026-09-15 UTC).
What an over-match looks like. Edit distance is measured over the whole name, so a long word
two names share can lift a score past 0.72 by itself. In the example’s capture, 13 of the 15
SAM.gov matches for “0DAY TECHNOLOGIES” share only the word “TECHNOLOGIES” with it:
“LUZY TECHNOLOGIES LLC” scored 0.824 because, once “LLC” is removed, 3 of its 17 characters
differ. Treat a fuzzy match as a lead to check, not as your vendor: compare matched_name,
address and exclusion_type before acting, and send state to get state_check on SAM.gov
matches.
The same record twice. SAM.gov’s extract sometimes lists a record more than once. Identical
rows are reported as one match with the count in source_record_count (2 for
“LIMITED 0DAY TECHNOLOGIES” in the capture). Rows that differ in name, address, state, exclusion
type or dates stay separate matches; the capture has three for “J & W TECHNOLOGIES LLC”.
Which name to send. Send the full registered legal name. A shorter trading name can score
under 0.72 against a longer listed name; when it is held back as a near miss, overall.reasons
tells you to re-screen with the full legal name. A name of two or more words that all appear in
the listed name scores 0.91. On the CSL section the query is compared with each record’s listed
name and every alias it lists, and matched_name is whichever scored highest. On the SAM.gov
section, a record is scored when a word of three or more characters from the name you send (or, if
it has none, the whole name) appears inside the listed name once spaces and hyphens are removed
from both, and listed names containing non-ASCII characters are also read and compared after
accents are folded. A misspelling in every longer word of a name can still keep a record from being
scored. If you hold more than one spelling of a vendor’s name, screen each.
Errors
Every error body is JSON: {"error": "<code>", "message": "<text>"}.
400 invalid_json: the body is not valid JSON, or a batch body is not a JSON object.400 invalid_entity: the body, or an entity in a batch, is not a JSON object.400 missing_fields:entity_nameis missing or blank.400 invalid_fields:entity_nameis longer than 512 characters, oraddress,state,ueiordunsis present but not a string.400 include_individuals_removed: the request sentinclude_individuals, which no longer exists.400 missing_entities:POST /screen/batchwithout a non-emptyentitiesarray.400 batch_too_large: more than 25 entities.401 unauthorized: the request did not carry the proxy credential RapidAPI adds.404 not_found: unknown route.405 method_not_allowed: wrong method for the route.500 provider_misconfigured,500 internal_error,503 service_misconfiguredand503 source_unavailable: a fault on our side. No screening result is returned; do not read any of them as a result, and retry later.
A source that fails during a screen is not an HTTP error: the response is 200, that section
reports status: "error", and overall.incomplete_coverage is true.
Further reading: SAM.gov’s Exclusions extract as data documents ten measured traps in the daily file this API screens against — the download that answers with a redirect, the layout that does not describe the file, the rows where Name is blank, the exclusion types that changed spelling, the rows that repeat another row under a new SAM Number, and the Dun & Bradstreet date test — with a runnable script and the counts from a dated run. What a screening API does not show you sets out the seven questions to ask of any screening response, including this one.
This API is advisory only. A “no potential matches found” result is never a certified
clearance, and every match requires independent human verification before declining,
suspending, or terminating a vendor relationship in reliance on it. See the API’s own
/terms endpoint for the full disclosure and disclaimer.
Not open for signups yet. It opens once its daily SAM.gov refresh has run cleanly on its own for several consecutive days and a final audit passes. Questions in the meantime: aerviklabs@gmail.com.