Changelog
Changelog

What's new.

Notable additions and changes to the API and developer experience. The API reference always reflects the current production spec.

  • 2026-09-16

    Adverse media: the matched name, phonetic recall and per-stage timings

    The matched name is the name that matched. For an ADVERSE_MEDIA match, matchedName is now the name found in the news source (the extracted person name, or the name in the headline), normalized to lowercase. It used to be the screened subject's own name, so every adverse-media hit was classified as an exact-name match. The evidence tier now follows the real comparison: a source name that differs from the subject's (for example anna marie for Anna Maria Eriksson) is a partial-name match and follows your partial-name decision rule, which can change the decision for tenants whose exact-name and partial-name rules differ. The subject's own name is used only when the source carries no name. Adverse-media hits are not dropped for sharing few name words with the subject. Watchlist, sanctions and PEP matching is unchanged. Data-subject exports keep the subject's own name on adverse-media matches.

    Phonetic name recall changed. A news name is now a candidate when it shares at least two phonetic codes with the subject's name, or a single code when the two names are also close in spelling. Some near-spellings that were missed before are now found; some weak names that shared only one phonetic code without being close in spelling are no longer matched.

    Per-stage timings. When a screen sets includeDiagnostics, diagnostics.stages lists each screening provider that ran: name, elapsedMs, outcome (ok, timedOut, failed or skipped), budgetMs, and the timed steps inside it.

  • 2026-08-29

    Every match now tells you who asserted it, and when

    Matched entities carry a new presentation object that splits a match into two zones: our decision — the conclusions this service is accountable for (classification, score, decision, risk band, rejection tag) — and, separately, one badged, timestamped block per data source that asserted anything about the subject, carrying what that source said and the moment we captured it. A source's claim is never rendered inside our decision zone, and never rendered without its name and capture time. Two sources matching one subject produce two evidence blocks and still one decision — sources are additive, the conclusion stays singular.

    Where it appears. On POST /v1/screenings/check, its idempotent replay, GET /v1/screenings/{id} and GET /v1/cases/{id}, and — as OUR DECISION / EVIDENCE sections — on the filed Match Details Report (PDF), whose CSV sibling gained evidenceProviders and evidenceCapturedAt columns appended at the end of the header. All of them are rendered from one builder, so a case re-read weeks later cannot disagree with the screen, or with the filed document, about who said what.

    Read presentation: null carefully. Null means "this read did not carry evidence" — it does not mean no source asserted anything. That answer is an empty evidence array, which is a real, assertable "nobody said anything". The bulk and batch listings return flat rows with no matches embedded, so they have no presentation field at all — follow each row's screeningId to GET /v1/screenings/{id} for its evidence.

    Additive and backwards-compatible. No existing field changed meaning, moved, or was removed; the CSV columns are appended, not inserted. kind, origin and producer are declared wire words (not enum ordinals and not .NET type names), so they survive internal renames — an unmapped value serialises as unrecognised, deliberately distinct from the legitimate producer unknown.

  • 2026-08-24

    Correction — the band policy names one match, not the whole screen

    This corrects the entry immediately below ("The exact-name rule now binds every tenant setting that can block"), which described the EscalateHighToFail gate as judged per screen: "it can still escalate a High-band Review to Fail as long as at least one match on the screen carries an exact name." That is no longer how it works. The earlier entry is left standing rather than rewritten, so anyone who integrated against it can see exactly what moved and when.

    What the gate does now. The band policy escalates only if it can name a carrier — one counted match that satisfies all three of: its own name is 100% identical; it is itself capable of blocking (its own decision is at least Review, so a match you have overridden to Pass, or whose warning type you switched off as a decision input, does not qualify); and its own contribution alone reaches the High band. With no carrier the escalation is clamped and the decision holds at Review, with NAME_NOT_EXACT recorded.

    Why it changed. "Any match on the screen" tied nothing to the match actually being blocked on. A second, unrelated hit was enough to re-authorise an automatic block on a name that is not identical — including a hit in a category that can never block on its own (adverse_media), and even one you had explicitly switched off. Expect strictly fewer automatic blocks under EscalateHighToFail, concentrated on multi-match screens; single-match screens are unaffected, and nothing is auto-cleared that was not cleared before. The three conditions are set out in full on Decision rules §3.

    Also new: the exact-name clamp is now visible per match. Every entry in factors[] carries an additive boolean nameIdentityClamped — true when that match resolved to Fail and was clamped to Review because its name is not identical. Read it per match, not as the screen's verdict: a screen can carry a clamped match and still block on a different one, so "decision": "Fail" alongside "nameIdentityClamped": true on one factor is the intended shape — it is the only place a suppressed automatic block is visible. It appears on the screening response, the case file and the regulator pack; it defaults to false, and screenings stored before this release read false.

  • 2026-08-24

    The exact-name rule now binds every tenant setting that can block

    Scope change to the rule in the entry below. "Automatic blocking requires a 100% identical name" previously governed only the decision matrix. It now binds every producer of a Fail but one. Concretely, two configurations that used to auto-block a name that was not character-identical no longer do: a per-warning-type decision override (setting, say, sanctions to Fail under WarningTypes) and the EscalateHighToFail band policy. Both are now clamped to Review when the name is not exact, and the case file records NAME_NOT_EXACT. The band policy is judged per screen: it can still escalate a High-band Review to Fail as long as at least one match on the screen carries an exact name.

    If you rely on either setting to block, expect fewer automatic blocks and more cases routed to an analyst — nothing is auto-cleared that was not cleared before. The one exemption is the post-screening EDD escalation (the PEP ladder in the entry below), which still Fails on a non-identical name by design; it is written by the pipeline and cannot be reached from tenant configuration. The full four-producer breakdown is on Decision rules §3.

    Two validation changes on PUT /v1/tenants/{id}/risk-profile. exactNameSimilarity is now restricted to [0.97, 1] — a value below 0.97 returns 400 where it previously returned 200. A low bar did not merely relax the rule, it also promoted every weak or partial name into an auto-blocking evidence tier, so "exactNameSimilarity": 0 would have turned the product into "block everything the matcher retrieves", silently. eddEscalationMaxClass now accepts "Unknown" and returns 200 where it previously returned 400; it is the documented off switch for the EDD ladder, escalating nothing while still recording the transparency notes. A numeric ordinal is still rejected for both.

  • 2026-08-24

    Decision rules — what may block automatically, and what now goes to an analyst

    This changes the decision some screens return. The direction of travel is consistent: an automatic Fail is reserved for evidence that actually identifies the person, and everything short of that is routed to a human instead of being blocked by a machine. Nothing is auto-cleared that was not cleared before — a watchlist hit can still never resolve to Pass on its own. Two outcomes flip: a sanctions match on an exact name where the list entry carries no date of birth was Fail and is now Review (this is the commonest sanctions shape — most OFAC entries carry no DoB — so it is the change most likely to show in your volumes), and an adverse-media match was Fail when the name and a full date of birth both agreed and is now Review. Every adverse-media tier is now Review: adverse media is a reported allegation, not an adjudicated blocking event.

    Automatic blocking now requires a 100% identical name. A name that is close but not character-for-character identical after normalisation is treated as an algorithmic variation — it still surfaces for an analyst, but it can no longer produce an automatic Fail, and the case file records NAME_NOT_EXACT so the downgrade is visible in the audit trail. Separately, a date of birth that is off by a small amount is now its own outcome: two full dates that differ but stay inside your DobYearTolerance land in a new fifth evidence tier, ExactNameDobNearMatch — a close match, resolved to Review in every category, where such a pair was previously absorbed into the confirmed tier and could block. Enhanced Due Diligence now applies across all four PEP classes at graduated intensity: escalation starts at the most sensitive class (class 1 — heads of state and government) and runs down to a ceiling you configure, with the classes below it recording a transparency note instead of escalating. Previously EDD escalated only class 4 (local government and associates) and left class 1 untouched.

    Two new tenant settings on the risk profile (GET/PUT /v1/tenants/{id}/risk-profile): ExactNameSimilarity (default 1.00 — set it to 0.97 to restore the previous near-exact blocking behaviour) and EddEscalationMaxClass (default National, the class-1 ceiling). Every softened cell remains one setting away from the stricter posture — set SanctionsUnconfirmedDecision = Fail, or override the individual cell — so a tenant that wants the previous behaviour keeps it without a code change. The full rule set, the decision matrix and every knob are documented on Decision rules.

    Integration note — the matched name field changed shape. For matches from the OpenSanctions provider, the name we report is now the alias that actually matched your subject rather than the entity's caption. If you parse or key on that field, expect a different string for the same entity. It appears in case files, CSV and PDF screening reports, regulator packs and GDPR exports.

  • 2026-08-07

    The named decision rules — DM-1, DM-2, DM-3

    Three named rules were written into the decision matrix so that the cells that depart from a naive "confirmed = name + date of birth" reading are stated openly rather than buried in the engine. DM-1: a sanctions entry carrying no date of birth — common on OFAC — can never reach the confirmed tier, so an exact name to it Failed on the name alone. DM-2: an adverse-media record where the name and a full date of birth both agreed Failed rather than merely reviewing. DM-3: an exact name whose full date of birth is present on both sides but differs beyond tolerance used to be dropped as a false positive — it passed by absence — and is now surfaced as a potential match for the matrix to decide, Review by default. DM-1 and DM-2 were superseded on 2026-08-24 (see the entry above); DM-3 stands. All three are documented, with rationales and worked examples, on Decision rules.

  • 2026-06-27

    Matching presets, named profiles & published benchmark

    Three system matching presets — Recall-first (new default, threshold 0.70), Balanced (0.80) and Precision-first (0.90) — tuned against an independent 1,736-name benchmark (overall recall 90.9%→95.1%). Tenants can now save named matching profiles, switch the active one and reset to a preset (/v1/tenants/{id}/matching-profiles). The tuning is published transparently on the new Matching benchmark page, and the playground gains a preset picker. Also fixed: mononym classification, leetspeak/digit de-fuzzing, and many-token timeouts.

  • 2026-06 · unreleased

    Developer docs portal

    This docs site launches at /docs, with a live API reference rendered from the production OpenAPI spec (/swagger/v1/swagger.json, now served read-only in all environments).

  • 2026-06

    Quotas, bulk & monitoring

    Per-tenant monthly screening quotas (GET /v1/usage, admin PUT …/quota), bulk screening (JSON or CSV, up to 1,000 rows) and ongoing monitoring with the monitoring.alert webhook.

  • 2026-06

    Signed webhooks

    HMAC-SHA256 webhook signatures (X-AML-Signature) with timestamp binding for replay protection. See Webhooks.

  • initial

    Screening core

    Single-call onboarding, sanctions / PEP / adverse-media screening with a Pass/Review/Fail decision and a risk band, plus idempotent screens.

This is a stub — entries will be dated and versioned as the API evolves. Breaking changes will be called out explicitly here.