Developer guide

UK sanctions API in Node.js: FCDO coverage and customer checks

Call the UK sanctions API from Node.js with native fetch. Select the FCDO UK Sanctions List and keep source references with each customer check.

250 free live screenings. One lifetime allowance. No credit card required.
On this page

Use FCDO coverage in a Node.js integration

Search your application’s configuration, fixtures and UI labels for legacy OFSI Consolidated List references. The UK Sanctions List publication explains the current government source and the January 2026 closure of the old consolidated list. A successful request to an old URL is not evidence of current coverage.

When using SanctionsKit, select the documented uk-sanctions source only after confirming availability. Keep its source identity with the result and create a new operation when changing coverage. Do not preserve an old source label merely because the surrounding JavaScript request code still works.

Prepare the synthetic exercise

Use the sandbox request to test a Node.js application migrating from an older OFSI-labeled integration. Keep old labels in historical results, but verify that the new operation records its selected source independently. Changing a UI label alone does not change which list a request checks.

Node.js setup and request files
RequirementValue or action
RuntimeUse Node.js 22 or later on a trusted server or CLI. This implementation uses the built-in fetch client and Node standard-library modules, so no SDK or npm dependency is required.
Client fileSave the client as screen.mjs.
Screening endpointPOST /api/v1/screenings
SANCTIONSKIT_API_KEYSandbox key; screenings:write and results:read scopes
SCREENING_OPERATION_IDPersist one operation ID; reuse only with the identical request body
request.jsonMira Calder: invented subject; sandbox@1: synthetic records
request.json: synthetic sandbox request
{
  "subject": {
    "name": "Mira Calder",
    "entityType": "person",
    "birthDate": "1984"
  },
  "package": "sandbox@1",
  "retention": "standard"
}

Implement the Node.js request boundary

The native-fetch client discovers production sources and verifies uk-sanctions before submission. When migrating configuration, compare that exact source ID with the result’s coverage rather than checking whether the human-readable name contains UK or OFSI.

Node.js: authenticated screening client
// Node.js 22+. Run on your trusted backend; no npm dependencies.
import { readFileSync } from 'node:fs';
const base = 'https://www.sanctionskit.com/api/v1';
async function main() {
  const key = process.env.SANCTIONSKIT_API_KEY;
  const operation = process.env.SCREENING_OPERATION_ID;
  if (!key || !operation) throw new Error('Set your key and operation ID.');
  const request = JSON.parse(readFileSync(process.argv[2] ?? 'request.json', 'utf8'));
  const sandbox = request.package === 'sandbox@1';
  const sourceIds = sandbox ? ['sandbox-synthetic'] : request.sources;
  if (!Array.isArray(sourceIds) || !sourceIds.length) throw new Error('Select your sources.');
  async function api(path, body) {
    const response = await fetch(base + path, {
      method: body ? 'POST' : 'GET', redirect: 'error', signal: AbortSignal.timeout(25000),
      headers: { Authorization: 'Bearer ' + key,
        ...(body ? { 'Content-Type': 'application/json', 'Idempotency-Key': operation } : {}) },
      ...(body ? { body: JSON.stringify(body) } : {}),
    });
    const envelope = await response.json();
    if (!response.ok) {
      const code = /^[a-z0-9_]{1,80}$/.test(envelope?.error?.code ?? '') ? envelope.error.code : 'unknown';
      throw new Error('API HTTP ' + response.status + ': ' + code);
    }
    return envelope?.data;
  }
  if (!sandbox) {
    const sources = await api('/sources');
    if (!Array.isArray(sources)) throw new Error('Invalid discovery response.');
    for (const id of sourceIds) {
      const found = sources.filter(source => source?.id === id);
      const source = found[0];
      if (found.length !== 1 || source.availability !== 'available' || source.fresh !== true ||
          !Array.isArray(source.capabilities) || !source.capabilities.includes(request.subject.entityType)) throw new Error('Required source unavailable or incompatible.');
    }
  }
  const result = await api('/screenings', request);
  if (typeof result?.id !== 'string' || !result.id || result.environment !== (sandbox ? 'sandbox' : 'production') ||
      !['potential_match', 'no_match'].includes(result.status) ||
      !Array.isArray(result.matches) || (result.status === 'no_match') !== (result.matches.length === 0) ||
      !Array.isArray(result.coverage) || result.coverage.length !== sourceIds.length ||
      sourceIds.some(id => result.coverage.filter(item => item.sourceId === id && item.fresh === true).length !== 1)) {
    throw new Error('Incomplete screening result.');
  }
  // Store result.id with your customer reference; use results:read to retrieve the evidence.
  console.log(JSON.stringify({ id: result.id, status: result.status,
    candidateCount: result.matches.length, sources: result.coverage.map(item => item.sourceId) }));
}
await main().catch(error => {
  console.error((/^API HTTP [0-9]{3}: [a-z0-9_]{1,80}$/.test(error.message) ||
    error.message === 'Required source unavailable or incompatible.')
    ? error.message : 'Screening incomplete. Check credentials, request and source coverage.');
  process.exitCode = 1;
});

Run the client

Run the sandbox request
node screen.mjs request.json

Confirm UK sanctions scope before production

The current government source is the FCDO UK Sanctions List. An old OFSI download or successful response from a retired integration is not a substitute for current coverage. Keep the UK list reference and stated measures visible when reviewing the candidate.

Production source-discovery contract
CheckRequired evidence
GET /api/v1/sourcesProduction key with sources:read; response data array
iduk-sanctions
availability / freshavailable / true
capabilitiesContains the requested subject.entityType
currentVersionActive version; retrieved_at and last_checked_at are not publication dates
lastImportMay describe an import that is not the active version
Missing or ineligible sourceInspect disabledReason; required coverage stays incomplete
Displayed clientPerforms production discovery before screening
Read source discovery with your production key
curl --fail-with-body --max-time 25 --header "Authorization: Bearer $SANCTIONSKIT_API_KEY" "https://www.sanctionskit.com/api/v1/sources"

Select uk-sanctions in the production request

Explicit change from the sandbox exercise
SettingProduction request
KeySeparate production credential with screenings:write
Coveragesources: ["uk-sanctions"]; omit package
Operation IDNew ID for the changed body and environment
UsageProduction access and screening allowance apply
SubjectOnly lawfully held, known identifying facts; no invented date precision
request.json: explicit uk-sanctions selection
{
  "subject": {
    "name": "Mira Calder",
    "entityType": "person",
    "birthDate": "1984"
  },
  "sources": [
    "uk-sanctions"
  ],
  "retention": "standard"
}

Interpret UK sanctions evidence in this workflow

Store data.coverage beside the new operation so a reviewer can distinguish it from earlier OFSI-labeled history. data.id links to retained evidence; a later rename of an application field must not rewrite which source an earlier screening actually used.

UK sanctions candidate fields to retain
Fields in data.matches[]Review use
record.id and record.sourceIdRetain the UK record reference and source identity when connecting the candidate to your customer.
record.names and birthDatesCompare original names and partial dates without inventing missing days or resolving similar names automatically.
record.designationsDisplay the available programs, legal references, effective dates and published wording beside the identity evidence.
  • data.id; data.coverage; data.versions; supplied disclaimer
  • data.matches[]: record, assessment, evidence, conflicts
  • GET /api/v1/results/{id}: results:read scope
  • Retained evidence and case review

Verify the application behavior

Recovery rules for the same saved operation
ConditionNext action
401 / 403Correct credentials or scopes before retrying
coverage_unavailable / stale_coverageKeep required coverage incomplete; no silent source substitution
Timeout after submissionRecover with the original Idempotency-Key and identical body
409Investigate an operation-key conflict
429 / 503Follow the specific error and Retry-After; an allowance cap may require a plan or usage change
Contract and safe diagnostic references
Operational reference
ReferenceUse
error.code / error.requestIdSafe recovery diagnostics; never log the submitted subject, key or full candidate response
potential_match / no_matchCompleted comparison outcomes; neither is an automatic business approval
  • Leave a legacy OFSI display label in a fixture and verify selection still uses uk-sanctions.
  • Reject a response whose coverage names a different source.
  • Keep a prior result unchanged when the new source configuration is saved.

Sources and references

Frequently asked questions

Must Node.js parse the UK government download for this tutorial?

No. The Node.js 22 client calls SanctionsKit and validates source discovery. Your work is the application boundary and review workflow; this example does not require an XML parser or government-feed import job.

Can an old OFSI label remain in a Node.js result history?

Preserve truthful historical context rather than rewriting earlier evidence. New checks should record the selected uk-sanctions source and current list context, so reviewers can distinguish a migration from a simple display-name change.

How does the Node.js UK example check source availability?

Before a production screening, it discovers the source and checks availability, freshness, and supported subject type. It then verifies the returned coverage includes the requested source. The API still checks eligibility when the screening arrives.

How can I test a UK source migration without a live subject?

Use invented subjects and mock the source-discovery and coverage responses. Confirm that the new source ID is required and that historical result labels remain intact. Those tests do not establish live source availability.