> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go.aiinsurance.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Screen Exposure For OFAC

> Runs a sanctions screening for one exposure and saves the result to it, in
one call: the values you send are submitted to the sanctions provider, the
normalized answer is written to the exposure's screening field, and that
answer is returned.

**Screening is advisory.** It never blocks a save, a quote, a bind, an
issue, or an import. A potential match is a similarity hit for a human to
review, never a determination that the party is sanctioned.

**The carrier turns screening on by configuration.** A screening runs
through a placed screening field: an exposure field of type
`Object: OfacScreening`, single-cardinality, placed on a card with the
**OFAC Screening** input modality. `fieldReferenceId` names that field. A
field that is not placed that way returns `400`
(`ofac-screening-field-not-placed`) and no provider call is made.

**You cannot choose the sanctions lists, the match threshold, or the
provider.** They are fixed platform settings, recorded on each result so a
reader knows what it covered. Sending `sources` or `minScore` is a `400`,
not a silently ignored key.

**`requestValues` replaces the request values wholesale.** Send the whole
set you want screened, not a patch — any request value you leave out is
cleared, because the saved record has to say what was actually submitted.
Omit `requestValues` entirely to re-screen the values already stored on the
exposure.

### 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, along with any
review decisions recorded against the previous run.

That makes retrying safe — a call that times out can simply be sent again,
and screening blocks nothing in the meantime — but it means a retry loop
costs a provider call each time. Retry a failed screening deliberately, not
automatically on a tight interval.

Re-screening is also how a sanctions-list update is picked up: a saved
result describes the list as of `screenedAt`, so a party cleared last month
is not cleared today.

### Reading the result

A result carries three independent axes — `status` (did the call happen),
`screeningOutcome` (what the provider returned), and `reviewOutcome` (what a
human concluded) — plus `screenedRequest`, the snapshot of what was
submitted. Compare the exposure's current screening values against that
snapshot to decide whether a saved result is still current; there is no
staleness flag.

A provider failure is a `200` with `status: failed`, not an HTTP error: the
failure is durably recorded on the exposure so it is visible rather than
lost. Reserve HTTP errors for requests that were refused.

### 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
the application UI). Automatic screening on import is deliberately deferred.

**Required permission:** `exposure.edit`




## OpenAPI

````yaml /openapi/generated-external-api.yaml post /api/v1/companies/{companyId}/ofac/screen
openapi: 3.0.3
info:
  title: AI Insurance External API
  description: External API for AI Insurance platform
  version: 1.0.0
  contact:
    email: support@aiinsurance.io
servers:
  - url: https://go.aiinsurance.io
    description: Production
security:
  - ApiKeyAuth: []
paths:
  /api/v1/companies/{companyId}/ofac/screen:
    post:
      tags:
        - OFAC Screening
      summary: Screen Exposure For OFAC
      description: >
        Runs a sanctions screening for one exposure and saves the result to it,
        in

        one call: the values you send are submitted to the sanctions provider,
        the

        normalized answer is written to the exposure's screening field, and that

        answer is returned.


        **Screening is advisory.** It never blocks a save, a quote, a bind, an

        issue, or an import. A potential match is a similarity hit for a human
        to

        review, never a determination that the party is sanctioned.


        **The carrier turns screening on by configuration.** A screening runs

        through a placed screening field: an exposure field of type

        `Object: OfacScreening`, single-cardinality, placed on a card with the

        **OFAC Screening** input modality. `fieldReferenceId` names that field.
        A

        field that is not placed that way returns `400`

        (`ofac-screening-field-not-placed`) and no provider call is made.


        **You cannot choose the sanctions lists, the match threshold, or the

        provider.** They are fixed platform settings, recorded on each result so
        a

        reader knows what it covered. Sending `sources` or `minScore` is a
        `400`,

        not a silently ignored key.


        **`requestValues` replaces the request values wholesale.** Send the
        whole

        set you want screened, not a patch — any request value you leave out is

        cleared, because the saved record has to say what was actually
        submitted.

        Omit `requestValues` entirely to re-screen the values already stored on
        the

        exposure.


        ### 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, along with
        any

        review decisions recorded against the previous run.


        That makes retrying safe — a call that times out can simply be sent
        again,

        and screening blocks nothing in the meantime — but it means a retry loop

        costs a provider call each time. Retry a failed screening deliberately,
        not

        automatically on a tight interval.


        Re-screening is also how a sanctions-list update is picked up: a saved

        result describes the list as of `screenedAt`, so a party cleared last
        month

        is not cleared today.


        ### Reading the result


        A result carries three independent axes — `status` (did the call
        happen),

        `screeningOutcome` (what the provider returned), and `reviewOutcome`
        (what a

        human concluded) — plus `screenedRequest`, the snapshot of what was

        submitted. Compare the exposure's current screening values against that

        snapshot to decide whether a saved result is still current; there is no

        staleness flag.


        A provider failure is a `200` with `status: failed`, not an HTTP error:
        the

        failure is durably recorded on the exposure so it is visible rather than

        lost. Reserve HTTP errors for requests that were refused.


        ### 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

        the application UI). Automatic screening on import is deliberately
        deferred.


        **Required permission:** `exposure.edit`
      operationId: screenExposureForOfac
      parameters:
        - $ref: '#/components/parameters/companyId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - fieldReferenceId
                - exposureId
              properties:
                fieldReferenceId:
                  type: string
                  description: |
                    The reference id of the exposure's placed screening field.
                exposureId:
                  type: string
                  format: uuid
                  description: |
                    The exposure to screen. It must belong to the company in the
                    path.
                requestValues:
                  allOf:
                    - $ref: '#/components/schemas/OfacScreeningRequestValues'
                  description: >
                    The values to screen. Replaces the exposure's current
                    request

                    values wholesale. Omit to screen what is already stored.
            examples:
              screenAName:
                summary: Screen a named individual
                value:
                  fieldReferenceId: ofacScreening
                  exposureId: 550e8400-e29b-41d4-a716-446655440030
                  requestValues:
                    name: Ada Lovelace
                    subjectType: person
                    citizenship: GB
              rescreenStoredValues:
                summary: Re-screen the values already on the exposure
                value:
                  fieldReferenceId: ofacScreening
                  exposureId: 550e8400-e29b-41d4-a716-446655440030
      responses:
        '200':
          description: |
            The screening ran. A provider failure is reported here as
            `status: failed`, not as an HTTP error.
          content:
            application/json:
              schema:
                type: object
                required:
                  - screening
                properties:
                  screening:
                    $ref: '#/components/schemas/OfacScreeningResult'
              examples:
                noMatches:
                  summary: Screened, nothing found
                  value:
                    screening:
                      name: Ada Lovelace
                      subjectType: person
                      status: completed
                      screeningOutcome: noMatches
                      reviewOutcome: notRequired
                      matches: []
                      screenedAt: '2026-09-01T14:32:07.884Z'
                      screenedBy: 550e8400-e29b-41d4-a716-446655440099
                      provider: ofacApiV4
                      sources: SDN, NONSDN
                      minScore: 100
                      screenedRequest:
                        name: Ada Lovelace
                        subjectType: person
                potentialMatches:
                  summary: Screened, potential matches pending review
                  value:
                    screening:
                      name: Ivan Testovich
                      subjectType: person
                      status: completed
                      screeningOutcome: matches
                      reviewOutcome: pending
                      matches:
                        - score: 100
                          sanctionName: TESTOVICH, Ivan
                          source: SDN
                          sourceId: SDN-1001
                          sanctionType: person
                          programs: EXAMPLE-PROGRAM
                          reviewDecision: null
                          reviewedBy: null
                          reviewedAt: null
                      screenedAt: '2026-09-01T14:35:11.204Z'
                      provider: ofacApiV4
                      sources: SDN, NONSDN
                      minScore: 100
                providerFailure:
                  summary: The provider could not be reached
                  value:
                    screening:
                      name: Ada Lovelace
                      status: failed
                      screeningOutcome: null
                      reviewOutcome: null
                      matches: null
                      failureCategory: Timeout
                      failureMessage: The screening service did not respond within 15000 ms.
        '400':
          description: >
            The request was refused and no provider call was made. Causes:

            `fieldReferenceId` does not name a single-cardinality

            `Object: OfacScreening` exposure field placed with the **OFAC

            Screening** input modality (`ofac-screening-field-not-placed`); the

            company's configuration declares no `OfacScreening` custom object

            (`ofac-screening-object-not-configured`); the

            screening values carry no `name` (`ofac-screening-name-required`);
            the

            values include a platform-written key such as `status` or `matches`

            (`ofac-screening-server-authored-values`); a value does not match
            the

            configured shape; `exposureId` is not a UUID; or the body carries an

            unrecognized key, including `sources`, `minScore` or `subject`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                fieldNotPlaced:
                  summary: The screening field is not placed for screening
                  value:
                    error:
                      code: ofac-screening-field-not-placed
                      message: >-
                        Field ofacScreening is not placed with the OFAC
                        Screening input modality
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: >
            No exposure with the given id exists for this company. Returned
            before

            any provider call, so another company's exposure is never submitted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  parameters:
    companyId:
      name: companyId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Company identifier
  schemas:
    OfacScreeningRequestValues:
      type: object
      description: >
        The values submitted to the sanctions provider — the caller-owned half
        of the

        OFAC screening object. Every value is typed by hand: nothing is mapped
        or

        pre-filled from other exposure fields.


        `name` is the only required member; it is the provider's one required
        field.


        A carrier may add its own sub-fields to the screening object, so a

        configuration can carry more keys than are listed here. Read the
        exposure's

        field configuration

        (`GET /entities/{entityType}/configuration`) for the authoritative
        shape.
      required:
        - name
      properties:
        name:
          type: string
          description: The name to screen. Required.
        subjectType:
          type: string
          nullable: true
          enum:
            - person
            - organization
            - vessel
            - aircraft
            - null
          description: The kind of party being screened.
        dob:
          type: object
          allOf:
            - $ref: '#/components/schemas/Fmv1Date'
          nullable: true
          description: Date of birth, for a person.
        gender:
          type: string
          nullable: true
          description: >
            Accepted by the provider as `m`, `f`, `male` or `female`. Values are

            lower-cased before submission; an unrecognizable value is omitted
            from

            the provider request rather than rejecting the whole screening.
        citizenship:
          type: string
          nullable: true
        nationality:
          type: string
          nullable: true
        phoneNumber:
          type: string
          nullable: true
        emailAddress:
          type: string
          nullable: true
        cryptoId:
          type: string
          nullable: true
          description: A cryptocurrency wallet identifier.
        address:
          type: object
          nullable: true
          description: The party's address.
          properties:
            address1:
              type: string
              nullable: true
            address2:
              type: string
              nullable: true
            city:
              type: string
              nullable: true
            stateOrProvince:
              type: string
              nullable: true
            postalCode:
              type: string
              nullable: true
            country:
              type: string
              nullable: true
        identifications:
          type: array
          nullable: true
          description: Identity documents belonging to the party.
          items:
            type: object
            properties:
              idNumber:
                type: string
                nullable: true
              idType:
                type: string
                nullable: true
                description: The kind of document, for example `passport`.
              country:
                type: string
                nullable: true
    OfacScreeningResult:
      type: object
      description: >
        A saved OFAC screening, as stored on the exposure. It holds both the
        values

        that were submitted and what came back, so a result explains itself
        without a

        second lookup: the request values live flat on this object alongside the

        result the platform wrote.


        **Three independent axes, never collapsed into one verdict:**


        * `status` — the OPERATIONAL axis: did the call happen at all.

        * `screeningOutcome` — the SCREENING axis: what the provider returned.

        * `reviewOutcome` — the REVIEW axis: what a human concluded.


        A failed call is neither `noMatches` nor `matches`; "the provider found

        nothing" and "a reviewer decided the hits were not this party" are
        different

        facts with different evidentiary weight.


        **Staleness is a comparison you make**, not a flag we set: a saved
        result

        applies to the values in `screenedRequest`. When the exposure's current

        screening values differ from that snapshot, the result describes a party
        that

        is no longer the one on record — re-screen.


        Everything except the request values and the per-match `reviewDecision`
        /

        `reviewNote` is written by the platform and is read-only.
      allOf:
        - $ref: '#/components/schemas/OfacScreeningRequestValues'
        - type: object
          properties:
            status:
              type: string
              nullable: true
              readOnly: true
              enum:
                - pending
                - completed
                - failed
                - null
              description: >
                Whether the provider call happened. Only `completed` and
                `failed` are

                ever stored — the call is synchronous, so `pending` never lands
                on a

                saved record.
            screeningOutcome:
              type: string
              nullable: true
              readOnly: true
              enum:
                - noMatches
                - matches
                - null
              description: >
                What the provider returned. `null` unless `status` is
                `completed`.
            reviewOutcome:
              type: string
              nullable: true
              readOnly: true
              enum:
                - notRequired
                - pending
                - cleared
                - confirmed
                - null
              description: >
                What human review concluded. `notRequired` when there were no

                potential matches; `pending` until every match has a decision;
                then

                `cleared` (all declined) or `confirmed` (any confirmed).
                Recomputed by

                the platform on every write — a value you send is ignored.
            matches:
              type: array
              nullable: true
              readOnly: true
              description: >
                The potential matches from this screening. A re-screen replaces
                this

                list wholesale, including any review decisions on it — those
                decisions

                were about a different screening.
              items:
                $ref: '#/components/schemas/OfacPotentialMatch'
            screenedRequest:
              type: object
              allOf:
                - $ref: '#/components/schemas/OfacScreeningRequestValues'
              nullable: true
              readOnly: true
              description: >
                The values actually submitted, snapshotted for provenance.
                Compare the

                exposure's current values against this to decide whether the
                result is

                still current.
            screenedAt:
              type: string
              nullable: true
              readOnly: true
              description: When the screening ran, as an ISO 8601 UTC instant.
            screenedBy:
              type: string
              nullable: true
              readOnly: true
              description: >
                The user id of whoever ran the screening. A screening run with
                an API

                key is attributed to the External API service user, not to the
                person

                who owns the key.
            provider:
              type: string
              nullable: true
              readOnly: true
              description: The sanctions data provider used, for example `ofacApiV4`.
            providerCaseId:
              type: string
              nullable: true
              readOnly: true
              description: |
                The stable case identifier submitted with the request, used to
                associate the provider's answer with this exposure and field.
            sources:
              type: string
              nullable: true
              readOnly: true
              description: |
                The sanctions lists screened against, comma-separated. A fixed
                platform setting, recorded so a reader knows what a saved result
                covered.
            minScore:
              type: number
              nullable: true
              readOnly: true
              description: >
                The similarity threshold used. A fixed platform setting,
                recorded for

                the same reason as `sources`.
            schemaVersion:
              type: number
              nullable: true
              readOnly: true
              description: The version of the stored screening shape.
            failureCategory:
              type: string
              nullable: true
              readOnly: true
              description: >
                Set when `status` is `failed`. One of `InvalidRequest`,
                `HttpError`,

                `NetworkError`, `Timeout`, `ProviderError` or `InvalidResponse`.
            failureMessage:
              type: string
              nullable: true
              readOnly: true
              description: |
                Set when `status` is `failed`: a human-readable explanation.
    ErrorResponse:
      type: object
      description: Standard error response for all external API endpoints
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Machine-readable error code
              example: VALIDATION_ERROR
            message:
              type: string
              description: Human-readable error message
              example: 'submissionId: Required field is missing'
            userMessages:
              type: array
              description: >-
                Clean, verbatim-displayable messages — one entry per failure,
                free of error-code tags, field paths, and internal noise.
                Suitable for showing to end users as-is.
              items:
                type: string
              example:
                - Exposures of type 'company' require an address
            details:
              type: array
              description: Additional details for validation errors (field-level errors)
              items:
                type: object
                properties:
                  field:
                    type: string
                    description: The field that caused the error
                    example: submissionId
                  code:
                    type: string
                    description: Stable problem code for this individual validation failure
                    example: BLANK_LIST_ELEMENT
                  reason:
                    type: string
                    description: Stable reason the value violates its canonical contract
                    example: blank-list-element
                  expected:
                    type: string
                    description: The expected canonical value contract
                    example: nonblank trimmed string
                  message:
                    type: string
                    description: Description of the field error
                    example: Required field is missing
    Fmv1Date:
      type: object
      description: >
        Field Model V1 `Date` value: a calendar day pinned to an IANA time zone
        —

        the day a person wrote on the policy, not an instant.


        `date` is the day as `YYYY-MM-DD` and must name a real calendar day

        (`2026-02-30` is rejected with `400`). `timezone` is an IANA tz database

        identifier (e.g. `America/New_York`, `UTC`); an unknown zone is rejected

        with `400`. On a write `timezone` may be omitted, in which case it
        defaults

        to `America/New_York`. Every value the API returns carries both members.


        This is the one Date shape the API accepts, stores and returns, for
        every

        field typed `Date` — entity fields, policy term dates, custom-object

        sub-fields, embedded exposure items and the event lifecycle dates alike.
        The

        retired `{ day, month, year, timezone }` spelling is refused with `400`

        (see the API changelog, 2026-09-08). The policy endorsement `deltas`
        channel

        additionally requires both members stated, because it stores each value

        exactly as sent (2026-09-04).
      required:
        - date
      additionalProperties: false
      properties:
        date:
          type: string
          format: date
          description: The calendar day as `YYYY-MM-DD`, zero-padded.
          example: '2026-03-15'
        timezone:
          type: string
          description: >
            IANA time zone identifier the day is anchored in (e.g.
            "America/New_York",

            "UTC"). Optional on a write (defaults to `America/New_York`); always

            present in a response.
          example: America/New_York
    OfacPotentialMatch:
      type: object
      description: >
        One **potential match** returned by the sanctions provider — a
        similarity hit

        against a sanctions list entry, never a determination that the screened
        party

        is that entry. Only a human review establishes anything more.


        The review fields are the record of that review. `reviewDecision` and

        `reviewNote` are yours to write through a normal entity update;
        `reviewedBy`

        and `reviewedAt` are stamped by the platform and are read-only.
      properties:
        score:
          type: number
          nullable: true
          description: The provider's similarity score for this hit.
        sanctionName:
          type: string
          nullable: true
          description: The name of the sanctions list entry that was matched.
        source:
          type: string
          nullable: true
          description: The sanctions list the entry came from, for example `SDN`.
        sourceId:
          type: string
          nullable: true
          description: The entry's identifier within its source list.
        sanctionId:
          type: string
          nullable: true
          description: The provider's identifier for the sanctions entry.
        sanctionType:
          type: string
          nullable: true
          description: The kind of party the sanctions entry describes.
        programs:
          type: string
          nullable: true
          description: |
            The sanctions programs the entry falls under, comma-separated.
        reviewDecision:
          type: string
          nullable: true
          enum:
            - confirmed
            - declined
            - null
          description: >
            What a reviewer concluded about this hit. `null` until it is
            reviewed.
        reviewedBy:
          type: string
          nullable: true
          readOnly: true
          description: >
            The id of the user recorded as making the decision. Stamped by the

            platform; a value you send is ignored. A decision written with an
            API key

            is attributed to the External API service user, not to the person
            who

            owns the key.
        reviewedAt:
          type: string
          nullable: true
          readOnly: true
          description: >
            When the decision was recorded, as an ISO 8601 UTC instant. Stamped
            by

            the platform; a value you send is ignored.
        reviewNote:
          type: string
          nullable: true
          description: An optional free-text note from the reviewer.
  responses:
    Unauthorized:
      description: Unauthorized - Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missingApiKey:
              summary: Missing API key
              value:
                error:
                  code: AuthenticationError
                  message: API key authentication required
                  userMessages:
                    - API key authentication required
            invalidApiKey:
              summary: >-
                Invalid API key (e.g. unknown key, or a Bearer token used
                instead of an API key)
              value:
                error:
                  code: AuthenticationError
                  message: Invalid API key
                  userMessages:
                    - Invalid API key
    Forbidden:
      description: Forbidden - Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            insufficientPermissions:
              summary: Insufficient permissions
              value:
                error:
                  code: AuthorizationError
                  message: User is not authorized to perform the requested action
                  userMessages:
                    - User is not authorized to perform the requested action
            companyMismatch:
              summary: A valid API key naming another company in the URL
              value:
                error:
                  code: AuthorizationError
                  message: API key is not scoped to the requested company
                  userMessages:
                    - API key is not scoped to the requested company
    InternalServerError:
      description: Internal Server Error - Unexpected error occurred
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            internalError:
              summary: Unexpected server error
              value:
                error:
                  code: UncaughtActionError
                  message: Uncaught error occurred in <actionName>
                  userMessages:
                    - An unexpected error occurred. Please try again later.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        API key authentication. Send your raw API key as the `Authorization`
        header value with NO scheme prefix — `Authorization: YOUR-API-KEY`. Do
        NOT prefix it with `Bearer ` or `ApiKey `, and do not use an `X-API-Key`
        header; those are not accepted.

````