Skip to main content
An exposure can be screened against OFAC sanctions lists through one action endpoint: It submits the values you send to the sanctions provider, saves the normalized answer to the exposure, and returns it. It requires exposure.edit — running a screening writes to the exposure, and needs no separate authority.

Screening is advisory

A screening blocks nothing: not a save, a quote, a bind, an issue, or an import. What comes back is a list of potential matches — similarity hits against sanctions entries, for a person to review. A hit is never a determination that the party you screened is the party on the list.

The carrier turns screening on

Screening runs through a placed screening field, and placing that field is the only on-switch. The carrier’s configuration needs an exposure field of type Object: OfacScreening, single-cardinality, placed on a card with the OFAC Screening input modality. The fieldReferenceId you send names that field. A company with no such field has no screening: the endpoint returns 400 (ofac-screening-field-not-placed) and nothing is submitted to the provider. Read GET /entities/{entityType}/configuration to discover the field and the screening sub-fields the carrier has configured.

What you can and cannot send

The values to screen — name, subject type, date of birth, address, identity documents and the rest — are yours. The server copies nothing from other exposure fields: it screens exactly what you send, or exactly what the exposure already holds when you omit requestValues. The carrier’s own users see one convenience this API does not have: an empty name box on the screening card starts out holding the exposure’s name, which they can overwrite before running. That is a form affordance in their browser, not a server rule — this endpoint screens when you call it and at no other time, and nothing about your writes triggers a screening. An exposure you create or update through the API is not screened until somebody asks. The sanctions lists, the match threshold and the provider are not yours to choose. They are fixed platform settings, recorded on every result so a reader knows what a saved screening covered. Sending sources or minScore is rejected with 400 rather than quietly ignored, so a caller can never believe it selected its own lists. requestValues replaces the stored request values rather than patching them: send the whole set you want screened, because the saved record has to say what was actually submitted. Omit it entirely to re-screen what the exposure already holds.

Reading a result

A result keeps three questions separate, because collapsing them into a single verdict loses information that matters: “The provider found nothing” and “a reviewer decided the hits were not this party” are different facts, so screeningOutcome and reviewOutcome never merge. A failed call is neither noMatches nor matches. A provider failure comes back as 200 with status: failed, not as an HTTP error. The failure is recorded on the exposure, where it stays visible; HTTP errors are reserved for requests that were refused. Review decisions are written through an ordinary entity update: set reviewDecision (and optionally reviewNote) on a match. The platform stamps reviewedBy and reviewedAt itself and recomputes reviewOutcome, so those are read-only. A screening or review made with an API key is attributed to External API in screenedBy / reviewedBy and in the app, not to the person who owns the key.

Staleness is a comparison, not a flag

Every result carries screenedRequest — a snapshot of the values actually submitted. A saved result describes those values, as of screenedAt, against the sanctions lists as they stood then. So there are two reasons a stored result may no longer be current, and you decide both:
  • The party changed. Compare the exposure’s current screening values against screenedRequest. If they differ, the result describes someone else.
  • The lists changed. Sanctions lists are updated frequently. A party cleared last month is not cleared today.

Retries and repeat calls

Every call is a fresh screening, and every call is billable. There is no idempotency key and no reuse of a recent result: a repeat request re-submits to the provider, and the new answer replaces the stored one — including any review decisions recorded against the previous run, which were about a different screening. This makes retrying safe. A call that timed out can simply be sent again, and because screening blocks nothing, nothing is stuck while you wait. It also means a retry loop costs a provider call every time it goes round, so retry a failed screening deliberately rather than automatically on a tight interval.

Importing exposures does not screen

Creating or updating an exposure through the entities API stores screening request values like any other field data and runs no screening — no provider call, no result. Screening happens only through this endpoint and through the application UI. This is deliberate. Screening on import is a decision we have deferred rather than ruled out; until then, screen imported exposures explicitly.