Skip to content
Business Risk
CONTINUOUS BUSINESS RISK API

A company does not become a risk on the day you look it up.

You verified it at onboarding. Since then a director resigned, an owner crossed 25% through a holding company, and an operator licence ran out. Send the record you hold (with the record you held last month) and get back the changes that are material, an effective-ownership chain multiplied all the way down, and a risk score whose every point is a named signal with a published weight.

Free tier: 100 assessments/month Paid from $499/month No card to run the demo
Live assessment Ready

Runs the same engine the paid endpoint uses, on the data in this box. Nothing is stored and no key is needed.

Press “Assess this entity” to call the live API.
The problem

Verification is a photograph. Risk is a film.

Onboarding checks a company once, writes down an answer, and moves on. The company keeps changing. The three things most likely to change are the three hardest to notice from a flat record.

The owner is not on the share register

Somebody holding 55% of a company that holds 60% of your counterparty controls 33% of it (over every beneficial-ownership threshold there is) and their name appears nowhere on the counterparty's own cap table. Finding them means multiplying percentages down a chain that nothing in a normal stack multiplies.

A re-check produces a diff, not an answer

Pull the record again and almost everything differs: a postcode reformatted, a name re-typed, a shareholder up a point. Somewhere in that list a director resigned. Without a rule for which differences matter, the alert queue trains people to ignore it.

Dates fail quietly

A licence has an expiry date and a status field, and they disagree: the status still says active a month after the date passed. Nothing errors. The permit simply is not valid any more, and the first anyone hears of it is the counterparty's regulator.

What it costs

Nothing alerts. The exposure just grows.

None of these is a system failure. Each is a fact about a counterparty that was true for months before anyone in your business could have known it.

  • Ownership
    A beneficial owner you never named

    Your file lists the holding company. The regime asks about the natural person at 25% or more. They are there (three quarters of the way up a chain of two) and the only thing between you and naming them is arithmetic nobody ran.

  • Status
    Credit extended to a company in administration

    The status changed in a filing. Your record still says active, because your record is a copy taken on the day you onboarded. Limits keep renewing against an entity whose control has passed to an insolvency practitioner.

  • Licence
    A permit that lapsed between annual reviews

    Licences expire on a date and are reviewed on a cycle, and the two are not aligned. Between the lapse and the next review the counterparty is operating unlicensed: and so, in the part of the transaction that is yours, are you.

What it computes

Five answers a flat record cannot give you.

Send the entity data your systems already hold. There is no registry lookup, no data vendor behind this and no model guessing: you supply the record, and the engine does the arithmetic deterministically, the same way every time.

OutputWhat it answersWhy it is hard by hand
Effective ownershipWho really owns this, once the chain is multiplied out.Percentages compound; floats drift across a 25.00% test.
Material changesWhich of the differences between two snapshots matter.Threshold crossings matter; raw deltas usually do not.
Risk signalsEvery named concern, with the points it contributed.A score with no breakdown is one nobody will act on.
Licence expiryDays remaining, and whether the licence is usable today.Status and expiry date disagree, and timezones bite.
Structure warningsLoops, unattributed share, holdings that lead nowhere.A cycle makes a naive traversal run forever.

Entity record Validated Ownership chain Signals Material changes Into your queue

  • 01

    The record in, checked

    Registration, status, officers, holdings, licences. Every percentage is an integer number of basis points; a subject that ends up more than 100% owned is a 400 naming the field, not an assessment nobody should act on.

  • 02

    Ownership multiplied down the chain

    Each holder's stake is the product of the holdings on every path to the entity, summed across paths. The arithmetic is exact integer arithmetic, not floating point, so a holder sitting on exactly 25.00% is reported on the same side of the line every time.

  • 03

    Loops found, depth bounded

    Circular ownership is real and a naive walk through it never stops. Loops are detected, reported as a path, and cut. Depth and total work are bounded, and if a bound stops the walk the output says so rather than looking complete.

  • 04

    Signals fired, weights published

    Each finding is a stable code with a documented weight and a plain-language detail. The score is the sum of the weights of the codes that fired, capped at 100. GET /v1/risk-signals returns the whole table, so you can re-derive any score by hand.

  • 05

    Changes classified

    Send last month's snapshot too. Every difference is reported, and each is marked material or not: a director resigning and an owner crossing 25% are material; a postcode reformatted and a stake moving 5% to 6% are not.

  • 06

    Whole UTC days, everywhere

    Licence expiry, officer tenure and entity age are computed on whole UTC days. An officer is not in post on their resignation date, and a licence is still valid on its expiry date: both stated, both tested, neither dependent on the server's clock.

Example output

Two snapshots in. Six signals, two material changes, one hidden owner.

The record in the demo panel above, as returned by POST /v1/assessments. Peter Vance holds nothing directly and controls a third of the company; last month he was one basis point under the line. Abridged: the full response also carries every officer, every licence and the band table.

{
  "entityId": "ent_88213",
  "score": 67, "band": "high",
  "scoring": {
    "contributions": [
      { "code": "ownership_unallocated_major",  "weight": 18 },
      { "code": "recent_ownership_shift",       "weight": 15 },
      { "code": "recent_officer_departure",     "weight": 12 },
      { "code": "indirect_beneficial_owner",    "weight": 8  },
      { "code": "licence_expiring_soon",        "weight": 8  },
      { "code": "sole_officer",                 "weight": 6  }
    ],
    "rawPoints": 67, "score": 67, "capped": false, "band": "high"
  },
  "ownership": {
    "thresholdBasisPoints": 2500,
    "owners": [
      { "holderName": "Meridian Holdings BV", "effectivePercent": "60.00%",
        "directBasisPoints": 6000, "beneficialOwner": true,  "indirect": false },
      { "holderName": "Peter Vance",          "effectivePercent": "33.00%",
        "directBasisPoints": 0,    "beneficialOwner": true,  "indirect": true  },
      { "holderName": "Amara Okonjo",         "effectivePercent": "15.00%",
        "directBasisPoints": 1500, "beneficialOwner": false, "indirect": false }
    ],
    "unallocatedBasisPoints": 2500, "cycles": [], "truncated": false
  },
  "licences": [
    { "licenceId": "lic_opr_2211", "daysRemaining": 14,
      "expiry": "expiring_soon", "effective": true }
  ],
  "changes": [
    { "code": "officer_resigned", "material": true, "subject": "Tom Brennan",
      "detail": "Tom Brennan (director) is no longer in post — resigned 2026-08-12." },
    { "code": "ownership_threshold_crossed_up", "material": true,
      "before": 2400, "after": 3300, "thresholdsBasisPoints": [2500],
      "detail": "Peter Vance crossed 25.00% upward: 24.00% to 33.00% effective ownership." }
  ],
  "changeSummary": { "total": 2, "material": 2, "informational": 0,
                     "hasMaterialChange": true }
}

18 + 15 + 12 + 8 + 8 + 6 = 67

That is the entire model. The score is the sum of the weights of the distinct codes that fired, capped at 100: no hidden term, no curve. A code counts once however many instances triggered it, so three expired licences are one expired-licence problem, not ninety points.

24.00% to 33.00%, not "+9%"

Peter Vance held 40% of a 60% holder, then 55% of it. Neither number is a direct holding, and the event worth an alert is not the size of the move: it is that a line at 25.00% was crossed. A holder going 5% to 6% is reported too, marked material: false.

You supply the record

Business Risk queries no registry, calls no data vendor and holds nothing about any real company. It assesses the fields in your request. The output is reproducible arithmetic on your data: not a credit decision, and not a legal determination.

This service is newly launched. We publish no uptime percentage, customer count, logo wall or certification claim until we have the operating history to support one.

How it works

Three steps to continuous monitoring

  • Assess the record you hold

    POST the entity. Back come weighted signals, a score, effective ownership through the whole chain and per-licence expiry. One unit per entity, up to 100 per call.

  • Keep the snapshot

    Store the record you sent. Next cycle, send the new one and the old one together. Nothing is stored here, so the snapshot you keep is the only state in the system: and it stays in your database.

  • Route on hasMaterialChange

    One boolean decides whether a human looks. Under it, every change carries a stable code, a materiality flag and a plain-language detail you can put straight in a case note.

Rules the engine never bends

Integer percentages, UTC days, bounded walks

  • Ownership is integer basis points, 10000 = 100%. A chain is multiplied exactly and rounded once, at the end: rounding at every hop reports stakes that are not there.
  • A crossing is the event, not the delta. 24.99% to 25.00% is material. 5% to 6% is not. Both are returned; only one is flagged.
  • Dates are whole UTC days. An officer is not in post on their resignation date. A licence is valid on its expiry date.
  • Every walk is bounded. Depth, total steps and cycles all have explicit limits, and hitting one is reported as a signal rather than hidden behind a plausible-looking answer.
  • Unknown is not fine. A status of unknown, an empty officer list and unattributed share all score. Absence of evidence is scored as absence of evidence.
  • Output is deterministic. Same record, same evaluation instant, same bytes: so a stored assessment can be diffed against the next one.
  • Nothing is stored. Every endpoint is stateless. The entity data you send is assessed and dropped.
Developer integration

Three endpoints, versioned, OpenAPI-first

Authenticate with Authorization: Bearer <key>. Every error returns a stable code and a requestId you can quote, and validation failures name the exact field in details.path.

POST/v1/keysPublic. Emails a one-time claim token to the address you give it. No key is returned on this call, proving the mailbox is what stops anyone minting a key on your account.
POST/v1/keys/claimPublic. Spends the emailed token and returns the key, shown once: 100 assessments a month, no card.
POST/v1/assessmentsAssess one entity or up to 100, with an optional previous snapshot each. Billed one unit per entity.
POST/v1/demo/assessPublic. Real engine, one entity, capped at 25 officers and 25 holdings. No key required.
GET/v1/risk-signalsPublic. Every signal code with its weight, the band cut-offs and every material-change code.
curl -X POST https://businessrisk-api.com/v1/assessments \
  -H "Authorization: Bearer $BUSINESS_RISK_KEY" \
  -H "content-type: application/json" \
  -d '{"entity":{"entityId":"ent_88213",
        "legalName":"Harbourline Logistics Ltd",
        "jurisdiction":"GB","status":"active",
        "officers":[{"officerId":"off_1","name":"Amara Okonjo",
                     "role":"director"}],
        "ownership":[
          {"holderId":"hold_meridian","holderType":"entity","basisPoints":6000},
          {"holderId":"ind_vance","holderType":"individual",
           "subjectId":"hold_meridian","basisPoints":5500}]}}'
Pricing

Priced per entity assessed, capped so a portfolio sweep can’t surprise you

One unit is one entity assessed: with or without a previous snapshot, because monitoring a company should not cost twice what checking it once does. Every plan includes an allowance, then a per-unit overage that is hard-capped per billing period: your worst-case bill is the base price plus the cap, never more.

Developer
$499 /month
  • 1,000 entity assessments included
  • $0.75 per additional entity assessment
  • Overage capped at $1,000 per period
  • Full API access, Python and TypeScript SDKs
Start with this plan
Scale
$5,000 /month
  • 20,000 entity assessments included
  • $0.35 per additional entity assessment
  • Overage capped at $10,000 per period
  • Full API access, Python and TypeScript SDKs
Start with this plan
Enterprise
$10,000+ /month
  • 60,000 entity assessments included
  • $0.25 per additional entity assessment
  • Overage capped at $20,000 per period
  • Full API access, Python and TypeScript SDKs
Contact sales

Free tier: 100 entity assessments per month, no card. Prices in USD, billed monthly. Payment is processed by Square through our shared billing platform; card details never touch this site.

Is this a company data source?
No, and it is important that you know that before you integrate. Business Risk queries no registry, calls no data vendor and stores nothing about any real company. You send the entity record your systems already hold; it assesses that record. If your data is stale, the assessment is an assessment of stale data: and that is why the change endpoint exists.
What counts as an assessment?
One entity in one call. A batch of 50 entities bills 50 units. Sending a previous snapshot alongside an entity still bills one unit: it is one entity assessed. Charging per snapshot would price continuous monitoring at double the price of a one-off check, which is exactly backwards.
What makes a change "material"?
A published rule per change code, returned by GET /v1/risk-signals. Broadly: threshold crossings, control-role officer changes, status transitions, jurisdiction moves, identity-field changes and licence lapses are material. Stake movements that cross nothing, address changes inside the same country, and re-typed names are not. Every difference is returned either way, with a material flag, so you can apply your own rule instead.
Why basis points instead of percentages?
Because effective ownership is a product, not a sum. Multiplying floating-point percentages down a chain accumulates error, and a holder sitting on exactly 25.00% then lands on either side of the regulatory line depending on the order the multiplications ran. Basis points are integers, the chain product is exact, and rounding happens once at the end.
Can I change the thresholds?
Yes. The beneficial-ownership threshold, the list of thresholds whose crossing is material, the licence warning window, the recent-incorporation window and the elevated-risk jurisdiction list are all per-request options. The jurisdiction list in particular is yours: we publish no country list and take no position on any jurisdiction.
Can I evaluate it before paying?
Yes. The demo at the top of this page is the real engine with no key at all, change detection included, and the free tier gives you 100 assessments a month against the full authenticated surface.

Find the change before it finds your loan book.

The free tier is 100 entity assessments a month, no card. Create a key, post one entity record, and the response names every owner the chain hides.

One email address, no password, no card. Prefer the terminal? The same key, in two calls:

curl -X POST https://businessrisk-api.com/v1/keys \
  -H "content-type: application/json" \
  -d '{"email":"you@company.com","name":"Evaluation key","source":{"source":"web","medium":"landing"}}'

# 202 Accepted. A one-time token is emailed to that address — spend it,
# and the response carries the key, shown once.

curl -X POST https://businessrisk-api.com/v1/keys/claim \
  -H "content-type: application/json" \
  -d '{"token":"<token from the email>"}'