---
title: "Retrieve a stored KYB check"
method: GET
path: "/kyb/checks/{id}"
tags: ["KYB"]
---

# Retrieve a stored KYB check

`GET /kyb/checks/{id}`

## Request

- Base URL: `https://api.companystack.co.uk`
- URL: `https://api.companystack.co.uk/kyb/checks/{id}`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-Api-Key`

Returns the result exactly as it was returned at the time of the check. Its PDF certificate is GET /kyb/checks/{id}.pdf, made and registered afresh on each download: fair use allows 300 an hour and 2,000 a day for each account, then 429 `fair_use_limit` with `Retry-After` (a refused or not-found download is not counted).

## Path parameters

- `id` string, required

## Response `200`

Stored result

- KybCheckResult: One KYB check, as returned and as stored (routes/kyb.ts).
  - `check_id` string, required
  - `company_number` string, required
  - `company_name` string, nullable
  - `reference` string, nullable
  - `outcome` 'pass' | 'refer' | 'fail' | 'unable_to_check', required: `unable_to_check`: nothing failed, but a check that matters could not run: the officers could not be read from Companies House and no copy is held (reason code OFFICERS_UNAVAILABLE), so no director was checked, or a register the check needs, such as the disqualified directors register, is not complete or current. Never a pass: run the check again later.
  - `summary` string
  - `reason_codes` string[], required
  - `warnings` string[]
  - `checks` object[], required
    - `check` string
    - `result` 'pass' | 'refer' | 'fail' | 'warn' | 'not_checked' | 'unable_to_check': `not_checked`: does not apply, or nothing is recorded to check. `unable_to_check`: should have run but a source could not be read just now, or a register it needs is not complete or current.
    - `reason_code` string, nullable
    - `message` string
    - `evidence` object
  - `sanctions` KybSanctions: Sanctions screening as a KYB check stores it. A name match is not a finding that anyone is sanctioned; each needs review. `strong_match` is shown as "Close name match" and needs date of birth or nationality / country corroboration; no name match is not a clearance.
    - `verdict` 'no_match' | 'possible_match' | 'strong_match' | 'unable_to_check', required: `unable_to_check`: no name match among the names screened, but the officers could not be read, so no director was screened.
    - `officers_status` 'cached' | 'fetched' | 'unavailable': How the officers were read: from the officers cache, from Companies House at the time, or not at all (not screened). Absent in checks stored before 2026-10-16.
    - `summary` string, required
    - `screened_at` string, date-time, required
    - `lists` object[], required: Every list: `current` and `stale` lists were screened (stale: not refreshed for 48 hours); `not_loaded` lists were not.
      - `id` 'uk_fcdo' | 'un_sc' | 'eu_fsf' | 'us_ofac_sdn' | 'us_ofac_cons' | 'ca_sema' | 'au_dfat' | 'nz_mfat' | 'jp_mof' | 'fr_tresor' | 'us_trade_csl' | 'ch_seco'
      - `name` string
      - `status` 'current' | 'stale' | 'not_loaded'
      - `published_at` string, date, nullable: The list's own publication date
      - `checked_at` string, date-time, nullable
      - `note` string, nullable
    - `subjects` object[], required
      - `role` string
      - `name` string
      - `result` 'no_match' | 'possible_match' | 'strong_match'
    - `not_screened` object[], required
      - `role` string
      - `name` string, nullable
      - `reason` string
    - `matches` object[], required
      - `subject_role` string
      - `subject_name` string
      - `verdict` 'possible_match' | 'strong_match'
      - `score` number: For sorting only: not a probability that the subject is the listed party, and not displayed
      - `list_id` string
      - `list_name` string
      - `entry_id` string
      - `listed_name` string
      - `matched_name` string
      - `programmes` string[]
      - `listed_on` string, date, nullable
      - `url` string, nullable
      - `agreed` string[]
      - `disagreed` string[]
      - `reasons` string[]
  - `facts` KybFacts
    - `charges` KybCharges: Counts of the company's charges as at a date, from CompanyStack's copy when it is proved complete and otherwise read from Companies House (every page). When they could not be read `available` is false: that is not a statement that the company has none.
      - `available` boolean, required
      - `total` integer: Every charge on the register, whatever its status (present when available)
      - `outstanding` integer
      - `part_satisfied` integer
      - `satisfied` integer
      - `other` integer: Charges with another status; total minus the three counts above
      - `as_at` string, date-time: When the list was last known to be current
      - `source` 'stored' | 'live'
      - `reason` string: Why the charges could not be read (present when available is false): companies_house_unavailable, companies_house_not_configured, incomplete_answer or list_too_long
      - `note` string, required
  - `data_as_of` string, nullable
  - `checked_at` string, date-time, required
  - `disclaimer` string: What the check covered, naming only the sanctions lists it actually screened
  - `notice` string: Who the data is prepared for and that CompanyStack accepts no responsibility to anyone else who relies on it (Terms 15B). Keep it with the data if you show it to others (Terms 17.5).

## Other responses

- `401`: API key missing, malformed or revoked
- `403`: The key's plan does not include this endpoint (`code: plan_upgrade_required`, with `upgrade_url`), the key may not call it, or the key is beyond the plan's key limit after a downgrade (`code: key_limit_exceeded`: the newest keys are paused until keys are deleted or the plan upgraded)
- `404`: Not found (or not yours)
- `429`: Per-minute or per-day limit reached (`code: rate_limited`, `window: minute|day`). Wait `Retry-After` seconds; when both windows are full the day is reported. A refused request does not count against either limit. A bulk lookup (`POST /company/bulk`) counts each company number in it as one request, so one that is more than you have left is refused whole, and the body adds `requested` and `fits`.

---

[API](https://skmtc.dev/companystack/apis/companystack-api.md) · [All operations](https://skmtc.dev/companystack/apis/companystack-api/llms.txt) · [OpenAPI document](https://skmtc.dev/companystack/apis/companystack-api/revisions/8f3234237d2d?raw)
