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

# Entity Deep Check

> Deep check: extended PEP/RCA exposure screening (#396), the Dutch insolvency
register on every tier (#403), adverse media on the extended tier (#402).

`pep_extended` is the source the base check does not return. /v1/entity/check
queries the same OpenSanctions collection but filters to sanctions/enforcement
datasets and reduces the answer to a boolean (app/services/sanctions.py); the
role.pep/role.rca detail is fetched and discarded. This endpoint keeps it.

`insolvency_records` is the Centraal Insolventieregister (NL only; for any other
country the field says `applicable: false`). It is queried by `kvk_number` when
the body carries one (exact), else by `entity_name` (trade-name search).

Two tiers, resolved from X-Response-Quality by the x402 middleware:
`fresh` (default; the `deep` tier, $0.75) returns pep_extended and
insolvency_records; `enhanced` (the `extended` tier, $1.50) adds
`adverse_media` from dilisense. There is no cache-only branch, so `cached` is
quoted, charged and served as `fresh`. If a source of the requested tier cannot
be reached the answer is a 503 (`pep_source_unavailable`,
`insolvency_source_unavailable` or `adverse_media_source_unavailable`), never
a fabricated clean screen, and the x402 gate settles only on a 2xx so the call
is not charged.



## OpenAPI

````yaml /api-reference/openapi.json post /v1/entity/deep-check
openapi: 3.1.0
info:
  title: LimitGuard.ai
  description: Trust Intelligence API - Entity verification and risk scoring
  version: 0.1.0
servers:
  - url: https://api.limitguard.ai
security: []
paths:
  /v1/entity/deep-check:
    post:
      summary: Entity Deep Check
      description: >-
        Deep check: extended PEP/RCA exposure screening (#396), the Dutch
        insolvency

        register on every tier (#403), adverse media on the extended tier
        (#402).


        `pep_extended` is the source the base check does not return.
        /v1/entity/check

        queries the same OpenSanctions collection but filters to
        sanctions/enforcement

        datasets and reduces the answer to a boolean
        (app/services/sanctions.py); the

        role.pep/role.rca detail is fetched and discarded. This endpoint keeps
        it.


        `insolvency_records` is the Centraal Insolventieregister (NL only; for
        any other

        country the field says `applicable: false`). It is queried by
        `kvk_number` when

        the body carries one (exact), else by `entity_name` (trade-name search).


        Two tiers, resolved from X-Response-Quality by the x402 middleware:

        `fresh` (default; the `deep` tier, $0.75) returns pep_extended and

        insolvency_records; `enhanced` (the `extended` tier, $1.50) adds

        `adverse_media` from dilisense. There is no cache-only branch, so
        `cached` is

        quoted, charged and served as `fresh`. If a source of the requested tier
        cannot

        be reached the answer is a 503 (`pep_source_unavailable`,

        `insolvency_source_unavailable` or `adverse_media_source_unavailable`),
        never

        a fabricated clean screen, and the x402 gate settles only on a 2xx so
        the call

        is not charged.
      operationId: entity_deep_check_v1_entity_deep_check_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeepCheckRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeepCheckResponse'
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: >-
            A source of the requested tier is unavailable — payment is not
            settled (#284)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - APIKeyHeader: []
components:
  schemas:
    DeepCheckRequest:
      properties:
        entity_name:
          type: string
          maxLength: 500
          minLength: 1
          title: Entity Name
          description: Legal entity or person name
        country:
          type: string
          maxLength: 2
          minLength: 2
          title: Country
          description: ISO 3166-1 alpha-2 country code
        kvk_number:
          anyOf:
            - type: string
            - type: 'null'
          title: Kvk Number
          description: >-
            Dutch KVK number (8 digits); enables an exact insolvency-register
            lookup
      additionalProperties: false
      type: object
      required:
        - entity_name
        - country
      title: DeepCheckRequest
      description: >-
        Request for POST /v1/entity/deep-check (#396, #403).


        Takes entity fields rather than an ``entity_id`` from a prior check: the
        audit

        trail is keyed by sha256(entity_name) and is one-way, so an id could not
        be

        resolved back to the name the screens have to query. ``kvk_number`` is
        optional

        and only consulted by the insolvency source (#403): the Centraal

        Insolventieregister keys ``searchUndertaking`` on the KvK number, which
        is an

        exact lookup where a trade-name search is a fuzzy one.
    DeepCheckResponse:
      properties:
        entity_name:
          type: string
          title: Entity Name
        country:
          type: string
          title: Country
        quality:
          type: string
          title: Quality
          description: deep (fresh) or extended (enhanced); see DEEP_CHECK_TIER_NAMES
          default: deep
        sources_returned:
          items:
            type: string
          type: array
          title: Sources Returned
          description: Sources actually run; equals EnhancedCheckHint.adds
        pep_extended:
          $ref: '#/components/schemas/PepScreenResult'
        adverse_media:
          anyOf:
            - $ref: '#/components/schemas/AdverseMediaResult'
            - type: 'null'
          description: >-
            Populated only on a tier whose adds include `adverse_media`. None
            means the tier did not include it -- never that a screen ran and
            found nothing.
        insolvency_records:
          anyOf:
            - $ref: '#/components/schemas/InsolvencyRecordsResult'
            - type: 'null'
          description: >-
            Dutch Centraal Insolventieregister screen; on every tier since #403.
            `applicable: false` (never null) when `country` is not NL.
        credit_report:
          anyOf:
            - $ref: '#/components/schemas/CreditReportResult'
            - type: 'null'
          description: >-
            Populated only on a tier whose adds include `credit_report`, and
            only for a country with a registered provider. None means the tier
            did not include it -- never that a screen ran and found no credit
            risk.
        processing_time_ms:
          type: integer
          minimum: 0
          title: Processing Time Ms
        disclaimers:
          items:
            type: string
          type: array
          title: Disclaimers
        sandbox:
          type: boolean
          title: Sandbox
          default: false
        version:
          type: string
          title: Version
          default: '1.0'
      type: object
      required:
        - entity_name
        - country
        - sources_returned
        - pep_extended
        - processing_time_ms
      title: DeepCheckResponse
      description: >-
        Response from /v1/entity/deep-check (#396, #402, #403).


        ``sources_returned`` is built from payment.DEEP_CHECK_TIER_ADDS[tier] --
        the same

        table enhanced_check_hint advertises -- so what was promised and what
        was delivered

        are one value. A name may only join that table together with the field
        that fills

        it on that tier.
    ErrorResponse:
      properties:
        type:
          type: string
          title: Type
          default: about:blank
        title:
          type: string
          title: Title
        status:
          type: integer
          title: Status
        detail:
          anyOf:
            - type: string
            - type: 'null'
          title: Detail
        instance:
          anyOf:
            - type: string
            - type: 'null'
          title: Instance
      type: object
      required:
        - title
        - status
      title: ErrorResponse
      description: RFC 7807 Problem Details response.
    PepScreenResult:
      properties:
        screened:
          type: boolean
          title: Screened
          description: True when OpenSanctions was actually queried
        pep_exposure:
          type: boolean
          title: Pep Exposure
          description: True when at least one role.pep/role.rca match cleared threshold
        match_count:
          type: integer
          minimum: 0
          title: Match Count
        matches:
          items:
            $ref: '#/components/schemas/PepMatch'
          type: array
          title: Matches
        truncated:
          type: boolean
          title: Truncated
          description: True when matches were capped
          default: false
        retrieved_at:
          type: string
          title: Retrieved At
          description: ISO 8601 UTC timestamp of the query
      type: object
      required:
        - screened
        - pep_exposure
        - match_count
        - retrieved_at
      title: PepScreenResult
      description: >-
        Result of the `pep_extended` source. `screened` is never False on a 200.


        There is no code path that returns this model without having queried

        OpenSanctions: app/services/pep.py raises rather than fabricating a
        clean screen,

        and the router turns that into a 503 so the payment is never settled
        (#284, #396).
    AdverseMediaResult:
      properties:
        screened:
          type: boolean
          title: Screened
          description: True when dilisense was actually queried
        adverse_media_found:
          type: boolean
          title: Adverse Media Found
          description: True when the vendor reported at least one news exposure
        match_count:
          type: integer
          minimum: 0
          title: Match Count
          description: Total exposures reported (total_hits)
        category_hits:
          additionalProperties:
            type: integer
          type: object
          title: Category Hits
          description: Exposures per dilisense category
        articles:
          items:
            $ref: '#/components/schemas/AdverseMediaArticle'
          type: array
          title: Articles
        truncated:
          type: boolean
          title: Truncated
          description: True when articles were capped below match_count
          default: false
        retrieved_at:
          type: string
          title: Retrieved At
          description: ISO 8601 UTC timestamp of the query
      type: object
      required:
        - screened
        - adverse_media_found
        - match_count
        - retrieved_at
      title: AdverseMediaResult
      description: >-
        Result of the `adverse_media` source. `screened` is never False on a
        200.


        Mirrors PepScreenResult: app/services/adverse_media.py raises rather
        than

        fabricating a clean screen, and the router turns that into a 503 so the
        payment

        is never settled (#284, #402). A negative means no *indexed reporting*
        matched,

        not that no wrongdoing exists; `screened` and `adverse_media_found` are
        separate

        fields so a caller can tell "looked, found nothing" from "did not look".
    InsolvencyRecordsResult:
      properties:
        screened:
          type: boolean
          title: Screened
          description: True when the register was actually queried
        applicable:
          type: boolean
          title: Applicable
          description: False when `country` is outside the register's jurisdiction (NL)
        jurisdiction:
          type: string
          title: Jurisdiction
          description: Jurisdiction the register covers
          default: NL
        query_by:
          anyOf:
            - type: string
            - type: 'null'
          title: Query By
          description: kvk_number or name; None when not applicable
        found:
          type: boolean
          title: Found
          description: True when at least one insolvency proceeding was listed
        match_count:
          anyOf:
            - type: integer
              minimum: 0
            - type: 'null'
          title: Match Count
          description: >-
            Identifiers the search returned; None when the register reported too
            many to list
        records:
          items:
            $ref: '#/components/schemas/InsolvencyRecord'
          type: array
          title: Records
          description: Up to 5 expanded cases
        truncated:
          type: boolean
          title: Truncated
          description: True when more cases exist than are returned
        retrieved_at:
          type: string
          title: Retrieved At
          description: ISO 8601 UTC timestamp of the query
      type: object
      required:
        - screened
        - applicable
        - found
        - truncated
        - retrieved_at
      title: InsolvencyRecordsResult
      description: >-
        Result of the `insolvency_records` source (#403).


        Unlike PepScreenResult and AdverseMediaResult, `screened` CAN be False
        on a 200:

        the register covers the Netherlands only, so for any other `country` the
        source

        is not consulted and the row says so with `applicable: false`. That is a

        different fact from a clean negative and must never be read as one. When

        `applicable` is True, `screened` is always True: every other failure
        raises and

        the router answers 503 (#284), so the caller is not charged.


        A negative result (`found: false`) means the register listed no
        insolvency

        proceeding for the KvK number or trade name at query time. Exception
        code 3

        ("too many results") is reported as `found: true, truncated: true,

        match_count: null` with no records: matches exist but the register will
        not

        list them until the query is narrowed (send `kvk_number`).


        Register conditions: no replica is kept and a successful screen is
        cached for at

        most 24 hours (app/config.py::cache_insolvency_ttl), inside the
        six-month

        destruction rule the subscription imposes.
    CreditReportResult:
      properties:
        screened:
          type: boolean
          title: Screened
          description: True when the provider was actually queried
        risk_score:
          type: string
          title: Risk Score
          description: 'Normalised verdict: green, yellow, red, or unknown'
        risk_band_available:
          type: boolean
          title: Risk Band Available
          description: True when the provider returned an assessment rather than grey/ND
        provider:
          type: string
          title: Provider
          description: Identifier of the provider queried
        country:
          type: string
          title: Country
          description: ISO 3166-1 alpha-2 country the provider covers
        organization_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Organization Name
          description: Company name as held by the provider
        identifier_type:
          anyOf:
            - type: string
            - type: 'null'
          title: Identifier Type
          description: 'Which identifier resolved the lookup: vat, tax or company_id'
        retrieved_at:
          type: string
          title: Retrieved At
          description: ISO 8601 UTC timestamp of the query
      type: object
      required:
        - screened
        - risk_score
        - risk_band_available
        - provider
        - country
        - retrieved_at
      title: CreditReportResult
      description: >-
        Result of the `credit_report` source. `screened` is never False on a
        200.


        Mirrors AdverseMediaResult: app/services/credit_report.py raises rather
        than

        fabricating a verdict, and the router turns that into a 503 so the
        payment is

        never settled (#284, #404). `screened` and `risk_score` are separate
        fields so a

        caller can tell "looked, low risk" from "did not look" -- and because
        coverage is

        per country, "no provider for this country" is a raised error, never a
        green

        verdict.


        A green score is the provider's assessment of the company at query time,
        not a

        guarantee of solvency and not a recommendation to extend credit.
        `risk_score` is

        a normalised value from a closed set (green / yellow / red / unknown),
        not the raw

        vendor string; `risk_band_available` is False when the provider declined
        to assess

        (its documented grey/ND answer, e.g. a closed company), which is a
        different fact

        from a low-risk verdict.
    PepMatch:
      properties:
        caption:
          type: string
          title: Caption
          description: Matched entity display name
        schema_type:
          type: string
          title: Schema Type
          description: FollowTheMoney schema, e.g. Person
        topics:
          items:
            type: string
          type: array
          title: Topics
          description: Risk topics, e.g. role.pep, role.rca
        datasets:
          items:
            type: string
          type: array
          title: Datasets
        score:
          type: number
          maximum: 1
          minimum: 0
          title: Score
          description: Match confidence
        countries:
          items:
            type: string
          type: array
          title: Countries
        birth_date:
          anyOf:
            - type: string
            - type: 'null'
          title: Birth Date
      type: object
      required:
        - caption
        - schema_type
        - topics
        - score
      title: PepMatch
      description: >-
        One OpenSanctions PEP/RCA match, projected to the fields we stand
        behind.
    AdverseMediaArticle:
      properties:
        headline:
          type: string
          title: Headline
          description: Article headline as indexed by the vendor
        source_link:
          type: string
          title: Source Link
          description: URL of the article
        category:
          type: string
          title: Category
          description: dilisense exposure category, e.g. financial_crime
        published_at:
          anyOf:
            - type: string
            - type: 'null'
          title: Published At
          description: ISO 8601 timestamp
        language:
          anyOf:
            - type: string
            - type: 'null'
          title: Language
          description: ISO 639-1 language code
        snippet:
          anyOf:
            - type: string
            - type: 'null'
          title: Snippet
          description: Bounded plain-text excerpt
      type: object
      required:
        - headline
        - source_link
        - category
      title: AdverseMediaArticle
      description: >-
        One adverse-media article, projected to the fields we stand behind
        (#402).


        Field names follow the dilisense `checkIndividual` article object
        (headline,

        source_link, timestamp, language, body). `snippet` is the body with its
        ``<p>``

        markup stripped and bounded; `category` is the news-exposure bucket
        dilisense

        filed the article under.
    InsolvencyRecord:
      properties:
        publication_id:
          type: string
          title: Publication Id
          description: publicatieKenmerk; the register's identifier for the case
        insolvency_number:
          anyOf:
            - type: string
            - type: 'null'
          title: Insolvency Number
          description: insolventienummer, e.g. F.13/24/123
        court:
          anyOf:
            - type: string
            - type: 'null'
          title: Court
          description: 'behandelendeInstantieCode: the court handling the case'
        subject_type:
          anyOf:
            - type: string
            - type: 'null'
          title: Subject Type
          description: >-
            legal_entity or natural_person, as the register classifies the
            insolvent party
        latest_publication:
          anyOf:
            - $ref: '#/components/schemas/InsolvencyPublication'
            - type: 'null'
      type: object
      required:
        - publication_id
      title: InsolvencyRecord
      description: >-
        One insolvency case from the Centraal Insolventieregister (#403).


        Projected from the getCase document to the fields we stand behind; the
        raw

        document is never echoed. Absent elements are None, not fabricated.
    InsolvencyPublication:
      properties:
        code:
          anyOf:
            - type: string
            - type: 'null'
          title: Code
          description: publicatieSoortCode from the register
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: publicatieOmschrijving from the register
        date:
          anyOf:
            - type: string
            - type: 'null'
          title: Date
          description: publicatieDatum as published (YYYY-MM-DD)
      type: object
      title: InsolvencyPublication
      description: >-
        The most recent publication on an insolvency case, as the register lists
        it.
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key

````