Appearance
High-risk geography
Geography as operations manage it: two tenant lists (where the business operates, where every onboarding gets a second look), a numeric geography score the integrating system attaches to the subject, and a rule set that sends review-band outcomes to a reviewer with a three-day SLA. Pack: examples/policies/high-risk-geography/.
A pattern for expressing a geography policy, not compliance guidance. The list rows are placeholders: AQ, BV and UM are uninhabited territories chosen so the example can run without the pack carrying any assessment of a real jurisdiction. Replace them with the tenant's own lists before anything depends on this.
The decision it automates
Whether a subject from a given country proceeds, is reviewed or is declined, where "which countries" is data that operations maintain through the lists API or the admin console, not a new version of a rule.
Data expected
- A subject with
data.country(ISO 3166-1 alpha-2) anddata.geoRiskScore, a number from 0 to 100 the integrating system computes however it likes (a vendor's country score, an internal model). - Two lists of kind
country:geo_supported_countriesandgeo_review_countries. The pack creates them with placeholder rows; importing it again adds only rows that are missing.
Steps and rules
| Step | Type | Why |
|---|---|---|
rules | evaluate_rules | The geo_risk rule set. |
route | branch | rules.outcome == manual_review opens a case. |
review | create_case | geo_review, priority medium, 72-hour SLA: enhanced review, not urgent. |
decide | emit_decision | From the rules, or the reviewer's decision. |
The rule set geo_risk sums weights into bands 0-40 approve, 40-90 manual_review, 90-100 reject:
| Rule | Type | Severity, weight | Behaviour |
|---|---|---|---|
geo_country_supported | list_lookup | block, 100 | mode: allow: fails when subject.country is not on geo_supported_countries |
geo_country_under_review | list_lookup | warn, 60 | mode: block: fails when the country is on geo_review_countries |
geo_risk_score | score_threshold | warn, 30 | contributeScore: true adds subject.geoRiskScore to the risk score whether or not the rule fails; above 70 it also fails |
So a review-list country alone scores 60 (review); with a geography score of 20 it is 80 (still review); with 30 or more it reaches 90 and rejects; an unsupported country rejects outright. A missing country fails both lookups; a missing or non-numeric score fails or errors the threshold rule, and an error always routes to review.
What a reviewer sees
A geo_review case with the three results: which list matched (with the row's reason), the score and the threshold. Lists are live data: a reviewer who concludes a country no longer needs the second look removes the row, and the next run behaves differently without a new version of anything (every list change is audited).
How to adapt it
Fill the lists from your own assessment through the CSV import (POST /lists/:key/import) or the admin console (Define › Lists); give rows an expiresAt for temporary measures. Read the country from a collection flow instead of the subject (submission.country) when the applicant declares it. Read the score from a vendor instead of geoRiskScore: a call_app step keeps the app's output under its outputKey, and the score_threshold points at <outputKey>.score. Use inList("geo_review_countries", data.subject.country) inside an expression rule when the geography should only matter in combination with another signal.
Run it
bash
pnpm policy:import examples/policies/high-risk-geography --publishThe fixture (expect.json) creates a merchant in AQ with a geography score of 20: supported passes, the review list fails (60), the score contributes 20, rules.riskScore is 80, a geo_review case opens, the check approves it and the run completes with a manual approve.