Skip to content

What is not built yet

An honest account of the gaps, checked against the code rather than against the design notes. The same principle the product runs on applies to its own documentation: a roadmap that quietly lists shipped work as pending, or omits a known hole, is the same failure as a green tick over an unrun check.

Verified on 2026-08-10.

The short version

GapBlocked onSize
Exposure fieldsA product decisionSmall build, large value
Periodic review schedulingNothingSmall
Applicant identity at intakeNothingSmall
Operator-attested VAT checkNothingSmall
Controls outputExposure fields firstMedium
Gates enforcingAn AML policy decisionSmall build
Four provider checksSpecs and agreementsBlocked
Entity and check webhooksNothingSmall
MATCH and VMSS connectionCard-scheme membershipMedium

Exposure fields

Nothing exists. No expected monthly volume, average ticket, delivery lead time, refund policy, recurring-versus-one-off, cross-border acceptance or prior PSP termination.

This is the largest hole in the risk model, and it is a hole of a different kind from the others. Every factor Verity scores today answers "is this merchant who they claim to be?". None answers "how much do we lose if they are not?"

A verified, clean, ten-year-old merchant selling event tickets with ninety-day delivery is a larger exposure to a PSP than an unverified corner shop — and Verity currently scores the corner shop higher.

Delivery lead time deserves singling out: prepayment for future delivery is weeks of chargeback liability, and travel and events are where PSPs die. It is one field.

Self-declared, and that is fine

These are values a merchant supplies, so under provenance they may raise risk freely and can never lower it below neutral. That is the correct treatment — a merchant claiming low volume should not earn a discount for saying so.

Blocked on deciding what to ask a merchant, which is a product decision rather than an engineering one. Four fields — volume, average ticket, delivery lead time, refund policy — would carry most of the value; a perfect form is not required to start.

Periodic review scheduling

entities.last_screened_at exists in the schema and nothing reads it. The only scheduled job in config/recurring.yml is Solid Queue cleanup.

Periodic reviews can be created, and they work. What does not exist is anything that opens one when a merchant is due, so a review cycle currently depends on somebody remembering.

This is a compliance-shaped gap rather than a feature gap, which is what makes it worth doing before larger work: the column is already there, and the failure mode is quiet.

Applicant identity

Verity records no applicant at all — nothing captures who submitted an application.

This is why the signer_not_verified_signatory gate can only ever report not assessed: there is no identity to match against the registered signatories. The risk design calls signatory identity assurance "the highest-value signal Verity owns", and it is unreachable for want of one intake field.

Capturing an applicant identity is small. Nafath authentication would make it strong, because Nafath proves the human is present rather than that someone knows their details.

VAT registration

No ZATCA lookup API exists — confirmed by research, not assumed. The only lookup is a CAPTCHA-gated human page, and ZATCA's published APIs are Fatoora e-invoicing, which cannot answer "is this merchant VAT-registered". Verity will not automate around a CAPTCHA: that means defeating an access control on a government system, and it breaks the moment they rotate it.

But there is a buildable version nobody has built: an operator-attested check. It records the VAT number, who verified it against the portal, when, and the outcome — the same shape as any other check, so it appears in coverage and expires on a review cycle, while being honest that a human read the page. The certificate can hang off it as an entity document.

The signal is worth having. VAT registration is mandatory above SAR 375,000 of revenue, so a merchant projecting SAR 2M while not registered is a contradiction worth escalating.

Controls output

entity_risk_controls is designed and does not exist.

"Medium risk" tells an underwriter nothing actionable. A PSP's mitigations are financial — rolling reserve percentage, settlement delay, volume cap, per-transaction cap, EDD, re-screening interval, manual review of the first N transactions.

The strongest argument for building it is that recommending controls makes the score falsifiable. You can check afterwards whether the controls were right. A band nobody can check is a band nobody learns from.

Worth building after exposure fields, because controls are largely a function of exposure. A reserve percentage recommended from data that cannot size a loss is a guess wearing a number.

Gates are advisory

Risk::Gates is never consulted by EntityReview. A triggered prohibited-activity gate recommends rejection and blocks nothing. The only hard block remains an unadjudicated sanctions match.

This is a deliberate open decision, and an AML policy call rather than an engineering one. The current direction is the safe default: making a gate enforcing later is straightforward, while making it advisory later would mean unblocking merchants who were already approved under the stricter rule.

Blocked provider checks

Four, each blocked on something engineering cannot obtain:

CheckBlocked on
investment_registration (Wathq MoI)An OpenAPI spec, or one captured response
power_of_attorney (Wathq)Same
vat_registration (ZATCA)An enterprise agreement — no public API exists at all
ecommerce_registration (Maroof)A Maroof API, or confirmation none exists

Without a contract an adapter would be invented rather than written, which is why these are stopped rather than attempted.

Two further Saudi sources — municipal_licence (Balady) and sector_licence (SFDA, CST) — have unconfirmed availability. The ISIC vocabulary already carries a regulating authority per activity code, which covers much of what those were wanted for.

Entity and check webhooks

Outbound webhooks cover review lifecycle events only. Nothing is emitted when a check completes or fails, or when an entity's risk band changes.

An integrator therefore has to poll to learn that a check finished — and since the entities endpoint is ordered by id rather than update time, polling it will not surface a recently-changed merchant either. Either an updated_since filter or check-level events would close this; events are the better answer.

Card scheme listings

Standing bars are built and enforcing: a barred national ID, registration number or IBAN blocks approval, and the data model already distinguishes an internal decision from a Mastercard MATCH or Visa VMSS listing.

What does not exist is a connection to either scheme. Listings are recorded by hand.

Access comes with card-scheme membership rather than with a payment-institution licence — Moyasar holds PI licences in Saudi Arabia and Bahrain, with the UAE following, and scheme access is being arranged. Until it lands, a compliance officer enters what an acquirer reports, which is honest about who established the fact.

Two things arrive with a real connection, and the second is easy to overlook:

  • Inbound — query before boarding, and import listings as entries
  • Outbound — MATCH is not read-only. An acquirer is obliged to add terminated merchants within a set window, so Verity's reason codes would need mapping onto Mastercard's, and lifting an internal bar stops being a purely internal act

Deliberately not built

Not everything absent is a gap.

registry_ownership_assertion (Wathq /v2/owns) — dropped as redundant. It takes no CR parameter, so it only says a person owns something; /v2/related answers the same question per-entity and with the relation type.

Wathq Ministry of Investment and Power of Attorney — deferred by decision as well as by missing specs. The commercial registration and contract payloads already carry parties, ownership percentages, manager authorities and representation rules.

A country risk table and a legal form ranking — these ship empty on purpose. Ranking legal forms is a credit judgement and a country risk table is a compliance artifact; an invented default would be worse than an obviously empty one. See factors and weights.

Suggested order

  1. Exposure fields — unblocked, highest value, needs a product decision on which fields
  2. Periodic review scheduling — the column exists and the failure mode is quiet
  3. Applicant identity at intake — unlocks a gate that is currently decorative
  4. Operator-attested VAT check — small, and closes a real signal without fighting a CAPTCHA
  5. Controls output — after exposure, or it recommends reserves from nothing