Skip to content
Browse documentation

Risk signals

Growth and Enterprise keys receive a risk_signals object on entity lookups and from the /risk endpoint. Flag codes are stable: they are only ever added, never renamed or removed, so you can match on them in code.

For how to read a score, especially when evidence is incomplete, see Interpreting risk signals.

Where risk_signals appears

SurfaceGrowth and EnterpriseFree
GET /v1/entity/{company_number}Top-level risk_signals key, computed from the sources in sources_checked (your tier's sources, or the ?sources= subset).risk_signals key omitted.
GET /v1/entity/{company_number}/riskcompany_number, risk_signals, fetched_at. Always fetches ch, ch_psc, insolvency, charges and officers.403 risk_tier_required
MCP lookup_uk_companySame as the entity lookup.risk_signals key omitted.
MCP get_company_riskSame as the /risk endpoint.risk_tier_required error.

On a Free key, treat a missing risk_signals key as "not entitled", never as "no risk".

Example

One flag triggered and one flag indeterminate because the insolvency source failed.

{
  "score": 20,
  "score_is_floor": true,
  "potential_score": 70,
  "coverage": ["ch", "ch_psc", "charges", "officers"],
  "flags": [
    {
      "code": "ACCOUNTS_OVERDUE",
      "severity": "warning",
      "description": "Company accounts are overdue",
      "triggered_at": "2026-10-12T09:41:07+00:00"
    }
  ],
  "indeterminate": [
    {
      "code": "INSOLVENCY_ACTIVE",
      "severity": "critical",
      "source": "insolvency",
      "reason": "source_unavailable"
    }
  ]
}

risk_signals object

Every field is present whenever the object is present.

FieldTypeDescription
scoreinteger0–100. Sum of the points of every triggered flag, capped at 100.
score_is_floorbooleantrue when indeterminate is non-empty. score is then a lower bound.
potential_scoreinteger0–100. score plus the points of every indeterminate flag, capped at 100. Equals score when indeterminate is empty.
coveragestring[]Risk-bearing sources consulted successfully for this score: requested, not failed, and not resolved unknown. A source absent from this list was not assessed.
flagsFlag[]Triggered flags. Empty array when none.
indeterminateIndeterminate[]Flags that could not be evaluated. Empty array when none.

Flag entry

One entry in flags. Points are not returned per flag; they are listed in the flag tables below.

FieldTypeDescription
codestringStable flag code. Match on this field.
severityenumcritical, warning or info.
descriptionstringHuman-readable summary for display. Wording can change.
triggered_atstring (ISO 8601)Time of the assessment that produced this response. Not the date the underlying condition began.

Indeterminate entry

One entry in indeterminate. It has no description or triggered_at.

FieldTypeDescription
codestringFlag code, from the same set as flags[].code.
severityenumcritical, warning or info: the severity the flag would carry if triggered.
sourcestringThe first of the flag's required sources that was unavailable.
reasonenumWhy the flag could not be evaluated. See below.

reason values

ValueEmittedMeaning
source_unavailableYesA required source failed, resolved unknown, or (for DIRECTOR_DISQUALIFIED) did not carry enough data to clear the flag. Often temporary.
not_requestedReservedThe caller scoped the source out. Not emitted today.
feature_disabledReservedThe source is switched off platform-wide. Not emitted today.

Handle unknown reason values without failing.

Indeterminacy rules

WhenResult
A required source failed during this request (the entity lookup also lists it in sources_failed).Every flag that requires it is indeterminate. The source is absent from coverage.
The charges or officers data resolved with status unknown.Treated as a failed source: same result as above.
DIRECTOR_DISQUALIFIED did not trigger, the company has at least one live director, and either officers.disqualification_checks.unknown_count is greater than 0 or the disqualification_checks rollup is missing. Only the first 10 live directors are checked, so later directors count as unknown.Only DIRECTOR_DISQUALIFIED is indeterminate. officers stays in coverage.
A source was not requested (for example ?sources=ch).Not indeterminate. Its flags appear in neither flags nor indeterminate, and the source is absent from coverage.

Source codes

Values that can appear in coverage, in indeterminate[].source and in the Required source(s) column below.

SourceDescription
chCompanies House company profile: status, company type, incorporation date, filing deadlines.
ch_pscCompanies House register of persons with significant control.
insolvencyInsolvency case records for the company.
chargesCompanies House register of charges (security interests).
officersCompanies House officers register, with a disqualification check for each live director.

Severity levels

SeverityDefinition
criticalA serious finding on its own: the company is insolvent or dissolved, or a live director is disqualified.
warningA compliance, governance or creditor issue that warrants review.
infoContext that is low-weight in isolation.

Flag codes

Each row links to itself, for example /docs/risk-signals#DIRECTOR_DISQUALIFIED. A flag is evaluated only when all its required sources are available; otherwise it is indeterminate.

Company status, filings and insolvency

CodeSeverityPointsRequired source(s)Fires when
INSOLVENCY_ACTIVEcritical+50insolvencyinsolvency.is_insolvent is true: at least one insolvency case on record has a status other than closed.
COMPANY_DISSOLVEDcritical+50chThe top-level status is dissolved.
ACCOUNTS_OVERDUEwarning+20chch.accounts_overdue is true.
CONFIRMATION_OVERDUEwarning+15chch.confirmation_overdue is true.
COMPANY_VERY_NEWinfo+5chch.incorporated_on is less than 90 days before the assessment.

People with significant control

CodeSeverityPointsRequired source(s)Fires when
NO_PSC_RECORDEDinfo+10ch_psc, chAll of: ch_psc.persons has no active PSC (it is empty, or every entry has a ceased_on date); ch.company_type is ltd or llp; ch.incorporated_on is more than 90 days before the assessment. Never fires for other company types, including plc. Does not change with include_ceased.

Charges

CodeSeverityPointsRequired source(s)Fires when
OUTSTANDING_CHARGESwarning+15chargescharges.status is present and outstanding_count + part_satisfied_count is greater than 0. Part-satisfied charges count as live. Satisfied-only history does not fire. Count-based, so a truncated items list cannot affect it.
ALL_ASSETS_CHARGEDwarning+10chargescharges.status is present and any item with status outstanding or part_satisfied has floating_charge_covers_all set to true. Reads items, so it can miss a charge when truncated is true. Normally fires with OUTSTANDING_CHARGES (+25 together).

Officers

A live director is an item in officers.items whose officer_role is director, corporate-director, nominee-director or corporate-nominee-director, with resigned_on null. The result does not change with include_resigned.

CodeSeverityPointsRequired source(s)Fires when
DIRECTOR_DISQUALIFIEDcritical+40officersofficers.disqualification_checks.disqualified_count is greater than 0: at least one live director has a disqualified verdict. Verdicts match on a Companies House identifier, never on a name alone. A disqualification whose disqualified_until date has passed reads as clear. A confirmed hit fires even when other directors could not be checked. Has an extra indeterminacy rule (see indeterminacy rules).
NO_ACTIVE_DIRECTORSwarning+20officersAll of: the top-level status is active; officers.status is present or none; there is no live director. An active company with a confirmed none officers record fires it.
SOLE_DIRECTOR_IS_CORPORATEinfo+10officersThere is exactly one distinct live director and its officer_role is corporate-director or corporate-nominee-director. Items sharing a non-null officer_id count once; items with a null officer_id each count separately.
IDENTITY_VERIFICATION_OVERDUEinfo+5officersAny live director has an identity_verification block with identity_verified_on null and an appointment_verification_statement_due_on date that has passed. A null block never fires.

Related