[{"data":1,"prerenderedAt":845},["ShallowReactive",2],{"navigation_docs":3,"-concepts-rules":183,"-concepts-rules-surround":840},[4,25,60,81,153,168],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting started",false,"\u002Fgetting-started","1.getting-started",[10,15,20],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F2.quickstart","i-lucide-zap",{"title":21,"path":22,"stem":23,"icon":24},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F3.installation","i-lucide-server",{"title":26,"icon":6,"path":27,"stem":28,"children":29,"page":6},"Concepts","\u002Fconcepts","2.concepts",[30,35,40,45,50,55],{"title":31,"path":32,"stem":33,"icon":34},"How AML works","\u002Fconcepts\u002Fhow-aml-works","2.concepts\u002F1.how-aml-works","i-lucide-book-open",{"title":36,"path":37,"stem":38,"icon":39},"Events and decisions","\u002Fconcepts\u002Fevents-and-decisions","2.concepts\u002F2.events-and-decisions","i-lucide-activity",{"title":41,"path":42,"stem":43,"icon":44},"Rules","\u002Fconcepts\u002Frules","2.concepts\u002F3.rules","i-lucide-scale",{"title":46,"path":47,"stem":48,"icon":49},"Alerts, cases and reporting","\u002Fconcepts\u002Falerts-cases-reporting","2.concepts\u002F4.alerts-cases-reporting","i-lucide-folder-search",{"title":51,"path":52,"stem":53,"icon":54},"Entities and the graph","\u002Fconcepts\u002Fentities-and-graph","2.concepts\u002F5.entities-and-graph","i-lucide-network",{"title":56,"path":57,"stem":58,"icon":59},"Audit log","\u002Fconcepts\u002Faudit-log","2.concepts\u002F6.audit-log","i-lucide-scroll-text",{"title":61,"icon":6,"path":62,"stem":63,"children":64,"page":6},"Guides","\u002Fguides","3.guides",[65,70,75],{"title":66,"path":67,"stem":68,"icon":69},"Guides by role","\u002Fguides\u002Fby-role","3.guides\u002F1.by-role","i-lucide-users",{"title":71,"path":72,"stem":73,"icon":74},"Integration plan","\u002Fguides\u002Fintegration-plan","3.guides\u002F2.integration-plan","i-lucide-list-checks",{"title":76,"path":77,"stem":78,"icon":79,"badge":80},"Connecting a rail","\u002Fguides\u002Fconnecting-a-rail","3.guides\u002F3.connecting-a-rail","i-lucide-plug","Coming soon",{"title":82,"icon":6,"path":83,"stem":84,"children":85,"page":6},"API reference","\u002Fapi","4.api",[86,91,96,101,106,111,116,121,126,129,134,139,144,149],{"title":87,"path":88,"stem":89,"icon":90},"Authentication","\u002Fapi\u002Fauthentication","4.api\u002F01.authentication","i-lucide-key-round",{"title":92,"path":93,"stem":94,"icon":95},"Errors","\u002Fapi\u002Ferrors","4.api\u002F02.errors","i-lucide-circle-alert",{"title":97,"path":98,"stem":99,"icon":100},"Idempotency","\u002Fapi\u002Fidempotency","4.api\u002F03.idempotency","i-lucide-repeat",{"title":102,"path":103,"stem":104,"icon":105},"Health","\u002Fapi\u002Fhealth","4.api\u002F04.health","i-lucide-heart-pulse",{"title":107,"path":108,"stem":109,"icon":110},"Entities","\u002Fapi\u002Fentities","4.api\u002F05.entities","i-lucide-user-round",{"title":112,"path":113,"stem":114,"icon":115},"Events","\u002Fapi\u002Fevents","4.api\u002F06.events","i-lucide-send",{"title":117,"path":118,"stem":119,"icon":120},"Decisions","\u002Fapi\u002Fdecisions","4.api\u002F07.decisions","i-lucide-gavel",{"title":122,"path":123,"stem":124,"icon":125},"Alerts","\u002Fapi\u002Falerts","4.api\u002F08.alerts","i-lucide-bell",{"title":41,"path":127,"stem":128,"icon":44},"\u002Fapi\u002Frules","4.api\u002F09.rules",{"title":130,"path":131,"stem":132,"icon":133},"Screening","\u002Fapi\u002Fscreening","4.api\u002F10.screening","i-lucide-user-search",{"title":135,"path":136,"stem":137,"icon":138},"API keys","\u002Fapi\u002Fapi-keys","4.api\u002F11.api-keys","i-lucide-key",{"title":140,"path":141,"stem":142,"icon":143},"Overview","\u002Fapi\u002Foverview","4.api\u002F12.overview","i-lucide-layout-dashboard",{"title":145,"path":146,"stem":147,"icon":148,"badge":80},"Webhooks","\u002Fapi\u002Fwebhooks","4.api\u002F13.webhooks","i-lucide-webhook",{"title":80,"path":150,"stem":151,"icon":152,"badge":80},"\u002Fapi\u002Fcoming-soon","4.api\u002F14.coming-soon","i-lucide-clock",{"title":154,"icon":6,"path":155,"stem":156,"children":157,"page":6},"Security and licensing","\u002Fsecurity","5.security",[158,163],{"title":159,"path":160,"stem":161,"icon":162},"Data flows","\u002Fsecurity\u002Fdata-flows","5.security\u002F1.data-flows","i-lucide-shield-check",{"title":164,"path":165,"stem":166,"icon":167,"badge":80},"Licensing and metering","\u002Fsecurity\u002Flicensing","5.security\u002F2.licensing","i-lucide-file-badge",{"title":169,"icon":6,"path":170,"stem":171,"children":172,"page":6},"Reference","\u002Freference","6.reference",[173,178],{"title":174,"path":175,"stem":176,"icon":177},"Glossary","\u002Freference\u002Fglossary","6.reference\u002F1.glossary","i-lucide-book-a",{"title":179,"path":180,"stem":181,"icon":182},"FAQ","\u002Freference\u002Ffaq","6.reference\u002F2.faq","i-lucide-circle-help",{"id":184,"title":41,"body":185,"description":833,"extension":834,"links":835,"meta":836,"navigation":837,"path":42,"seo":838,"stem":43,"__hash__":839},"docs\u002F2.concepts\u002F3.rules.md",{"type":186,"value":187,"toc":816},"minimark",[188,197,207,212,223,226,238,241,246,370,373,511,524,528,543,546,550,577,581,584,693,700,704,707,776,780],[189,190,191,192,196],"p",{},"A ",[193,194,195],"strong",{},"rule"," is a true-or-false expression over an event and its features, plus a weight. When it's true, its weight is added to the score and its reason is recorded.",[189,198,191,199,202,203,206],{},[193,200,201],{},"typology"," is the real-world pattern a rule is trying to catch, such as \"fan-in to a mule wallet\". A ",[193,204,205],{},"typology pack"," is a ready-made set of rules for common patterns.",[208,209,211],"h2",{"id":210},"the-rule-language","The rule language",[189,213,214,215,222],{},"Rules are written in the ",[216,217,221],"a",{"href":218,"rel":219},"https:\u002F\u002Fcel.dev",[220],"nofollow","Common Expression Language (CEL)",", a small expression language from Google that can't loop forever or touch the network. An expression is compiled when you save it, so a broken one is rejected then and never reaches a live payment.",[189,224,225],{},"Here is a rule from the built-in pack:",[227,228,235],"pre",{"className":229,"code":231,"filename":232,"language":233,"meta":234},[230],"language-text","key      structuring_below_threshold\nversion  1\nweight   60\nexpr     amount >= 4500.0 && amount \u003C 5000.0\n         && features[\"near_threshold_count_24h\"] >= 3\ndetail   repeated transfers just below the reporting threshold within 24h\n","structuring_below_threshold","text","",[236,237,231],"code",{"__ignoreMap":234},[189,239,240],{},"The thresholds in the built-in pack are placeholders. Set them to match your own reporting limits.",[242,243,245],"h3",{"id":244},"variables","Variables",[247,248,249,265],"table",{},[250,251,252],"thead",{},[253,254,255,259,262],"tr",{},[256,257,258],"th",{},"Variable",[256,260,261],{},"Type",[256,263,264],{},"Value",[266,267,268,282,299,315,331,345,358],"tbody",{},[253,269,270,276,279],{},[271,272,273],"td",{},[236,274,275],{},"type",[271,277,278],{},"string",[271,280,281],{},"The event type",[253,283,284,289,292],{},[271,285,286],{},[236,287,288],{},"amount",[271,290,291],{},"double",[271,293,294,295,298],{},"Amount value, ",[236,296,297],{},"0"," if none",[253,300,301,310,312],{},[271,302,303,306,307],{},[236,304,305],{},"currency",", ",[236,308,309],{},"rail",[271,311,278],{},[271,313,314],{},"As sent, or empty",[253,316,317,322,324],{},[271,318,319],{},[236,320,321],{},"source_id",[271,323,278],{},[271,325,326,327,330],{},"The event's ",[236,328,329],{},"source.entity_id",", or empty",[253,332,333,338,340],{},[271,334,335],{},[236,336,337],{},"destination_id",[271,339,278],{},[271,341,326,342,330],{},[236,343,344],{},"destination.entity_id",[253,346,347,352,355],{},[271,348,349],{},[236,350,351],{},"features",[271,353,354],{},"map of string to int",[271,356,357],{},"Counters for the source",[253,359,360,365,367],{},[271,361,362],{},[236,363,364],{},"dest_features",[271,366,354],{},[271,368,369],{},"The same counters for the destination",[189,371,372],{},"Money moves from the source to the destination. Every counter covers the 24 hours up to and including this event, and only events that had already arrived when this one did.",[247,374,375,385],{},[250,376,377],{},[253,378,379,382],{},[256,380,381],{},"Counter",[256,383,384],{},"Counts",[266,386,387,397,414,424,434,444,454,464,473,483,496],{},[253,388,389,394],{},[271,390,391],{},[236,392,393],{},"txn_count_24h",[271,395,396],{},"Events the source sent",[253,398,399,404],{},[271,400,401],{},[236,402,403],{},"near_threshold_count_24h",[271,405,406,407,410,411],{},"Of those, how many were just under the reporting threshold: from 4,500 up to but not including 5,000 unless you set ",[236,408,409],{},"SENTINEL_NEAR_THRESHOLD_LOW"," and ",[236,412,413],{},"SENTINEL_NEAR_THRESHOLD_HIGH",[253,415,416,421],{},[271,417,418],{},[236,419,420],{},"in_count_24h",[271,422,423],{},"Payments the entity received",[253,425,426,431],{},[271,427,428],{},[236,429,430],{},"in_value_24h",[271,432,433],{},"Their total, in whole units",[253,435,436,441],{},[271,437,438],{},[236,439,440],{},"in_senders_24h",[271,442,443],{},"How many different senders paid it",[253,445,446,451],{},[271,447,448],{},[236,449,450],{},"in_senders_1h",[271,452,453],{},"The same, in the last hour",[253,455,456,461],{},[271,457,458],{},[236,459,460],{},"out_count_24h",[271,462,463],{},"Payments the entity made",[253,465,466,471],{},[271,467,468],{},[236,469,470],{},"out_value_24h",[271,472,433],{},[253,474,475,480],{},[271,476,477],{},[236,478,479],{},"out_receivers_24h",[271,481,482],{},"How many different receivers it paid",[253,484,485,490],{},[271,486,487],{},[236,488,489],{},"dormant_days",[271,491,492,493,495],{},"Whole days since its previous payment in or out, ",[236,494,297],{}," if it has none",[253,497,498,503],{},[271,499,500],{},[236,501,502],{},"seen_before",[271,504,505,508,509],{},[236,506,507],{},"1"," if it had any earlier payment, otherwise ",[236,510,297],{},[189,512,513,514,516,517,519,520,523],{},"A counter that doesn't apply reads as ",[236,515,297],{},", so a rule never fails on a missing key. Values add up amounts in whatever currency the events used; Sentinel doesn't convert between currencies. Compare ",[236,518,288],{}," with a decimal (",[236,521,522],{},"4500.0","), because CEL won't compare a double with a whole number.",[242,525,527],{"id":526},"who-a-rule-is-about","Who a rule is about",[189,529,530,531,534,535,538,539,542],{},"Each rule has a ",[236,532,533],{},"subject",": ",[236,536,537],{},"source"," (the default) or ",[236,540,541],{},"destination",". It decides whose alert a match goes on. A fan-in rule looks at money arriving at the destination, so it's about the destination, and its alert is on the receiving wallet rather than on one of the many senders.",[189,544,545],{},"When rules about both parties fire on the same event, the alert goes to the party whose rules added more points.",[208,547,549],{"id":548},"scoring","Scoring",[551,552,553,557,568,571,574],"ul",{},[554,555,556],"li",{},"Every active rule runs on every event scored in sync mode. The weights of the rules that match are added up and capped at 100.",[554,558,559,560,563,564,567],{},"A score of 50 or more is ",[236,561,562],{},"review",", and 90 or more is ",[236,565,566],{},"block",". These thresholds are fixed in the current release.",[554,569,570],{},"Reasons are stored with the rule key and version, so a decision from last year can still be explained exactly.",[554,572,573],{},"If a rule errors at run time, it's skipped and the error is logged. It's never quietly treated as \"didn't match\".",[554,575,576],{},"The counter values used, for both parties, are stored with the decision, so the inputs are kept as well as the outcome.",[208,578,580],{"id":579},"the-built-in-pack","The built-in pack",[189,582,583],{},"An organisation with no active rules of its own is scored by six built-in rules. Their thresholds are placeholders until they're tuned with real data; set your own to match your reporting limits and customers.",[247,585,586,602],{},[250,587,588],{},[253,589,590,593,596,599],{},[256,591,592],{},"Key",[256,594,595],{},"About",[256,597,598],{},"Weight",[256,600,601],{},"Fires when",[266,603,604,619,634,650,664,678],{},[253,605,606,610,613,616],{},[271,607,608],{},[236,609,232],{},[271,611,612],{},"sender",[271,614,615],{},"60",[271,617,618],{},"The amount is just under the threshold and the sender has made 3 or more such transfers in 24 hours",[253,620,621,626,628,631],{},[271,622,623],{},[236,624,625],{},"high_velocity_24h",[271,627,612],{},[271,629,630],{},"30",[271,632,633],{},"The sender has made 20 or more transactions in 24 hours",[253,635,636,641,644,647],{},[271,637,638],{},[236,639,640],{},"fan_in_unrelated_senders",[271,642,643],{},"receiver",[271,645,646],{},"50",[271,648,649],{},"10 or more different senders paid the receiver within an hour",[253,651,652,657,659,661],{},[271,653,654],{},[236,655,656],{},"fan_out_after_credit",[271,658,612],{},[271,660,646],{},[271,662,663],{},"The sender received 5,000 or more and paid 10 or more different receivers within 24 hours",[253,665,666,671,673,675],{},[271,667,668],{},[236,669,670],{},"dormant_then_active",[271,672,643],{},[271,674,646],{},[271,676,677],{},"The receiver had no activity for 90 days or more and now gets 1,000 or more",[253,679,680,685,687,690],{},[271,681,682],{},[236,683,684],{},"pass_through",[271,686,612],{},[271,688,689],{},"40",[271,691,692],{},"The sender paid out 90% or more of the 5,000 or more it received within 24 hours",[189,694,695,696,699],{},"As soon as you activate a rule of your own, only your active rules run. To keep the built-in rules and edit them like any other, run ",[236,697,698],{},"sentinel-admin rules seed -org \u003Corg>"," first. It installs them as active rules, and only works while the organisation has no rule versions.",[208,701,703],{"id":702},"changing-a-rule-safely","Changing a rule safely",[189,705,706],{},"Rules are versioned. You never edit a live rule. You create a new version, and a second person approves it.",[708,709,711,715,729,733,743,747,757,761],"steps",{"level":710},"3",[242,712,714],{"id":713},"draft","Draft",[189,716,717,718,721,722,728],{},"Write the rule on the ",[193,719,720],{},"New rule"," screen, or with ",[216,723,725],{"href":724},"\u002Fapi\u002Frules#create-a-draft",[236,726,727],{},"POST \u002Fv1\u002Frules",". Using an existing key creates that rule's next version. Nothing changes in production.",[242,730,732],{"id":731},"backtest","Backtest",[189,734,735,736,742],{},"Replay the draft against stored events with ",[216,737,739],{"href":738},"\u002Fapi\u002Frules#backtest-a-version",[236,740,741],{},"POST \u002Fv1\u002Frules\u002F{id}\u002Fbacktest",", or from the rule's page in the dashboard. You see how many events it would have flagged and, if another version is live, how many it would newly flag and how many it would stop flagging. This stops you flooding analysts by accident.",[242,744,746],{"id":745},"approve","Approve",[189,748,749,750,756],{},"Someone with a different API key activates it with ",[216,751,753],{"href":752},"\u002Fapi\u002Frules#activate-a-draft",[236,754,755],{},"POST \u002Fv1\u002Frules\u002F{id}\u002Factivate",". The key that wrote the draft can't approve it.",[242,758,760],{"id":759},"live","Live",[189,762,763,764,767,768,771,772,775],{},"The new version is ",[236,765,766],{},"active"," and the old one is ",[236,769,770],{},"retired",". Every version is kept, with who wrote it and who approved it, and both actions are in the ",[216,773,774],{"href":57},"audit log",".",[208,777,779],{"id":778},"not-built-yet","Not built yet",[551,781,782,788,794,800,810],{},[554,783,784,787],{},[193,785,786],{},"Shadow mode",", where a rule scores live events without affecting decisions.",[554,789,790,793],{},[193,791,792],{},"Precision tracking",": how often a rule's alerts turn out to be real.",[554,795,796,799],{},[193,797,798],{},"Configurable decision thresholds."," Review at 50 and block at 90 are fixed.",[554,801,802,805,806,809],{},[193,803,804],{},"Device and phone counters",", such as several wallets sharing one device. Events can carry a ",[236,807,808],{},"device"," but nothing counts it yet.",[554,811,812,815],{},[193,813,814],{},"Maintained typology packs"," delivered as signed updates. The planned packs cover fan-in and fan-out, structuring, dormant accounts waking up, round-tripping, agent self-dealing, SIM swap followed by a drain, shared devices and IDs, pass-through accounts, high-risk corridors, and card patterns such as card testing.",{"title":234,"searchDepth":817,"depth":817,"links":818},2,[819,824,825,826,832],{"id":210,"depth":817,"text":211,"children":820},[821,823],{"id":244,"depth":822,"text":245},3,{"id":526,"depth":822,"text":527},{"id":548,"depth":817,"text":549},{"id":579,"depth":817,"text":580},{"id":702,"depth":817,"text":703,"children":827},[828,829,830,831],{"id":713,"depth":822,"text":714},{"id":731,"depth":822,"text":732},{"id":745,"depth":822,"text":746},{"id":759,"depth":822,"text":760},{"id":778,"depth":817,"text":779},"How rules are written, how they add up to a score, and how to change one safely.","md",null,{},{"icon":44},{"title":41,"description":833},"Dtn1Y7N4prTXl8aXLO4lfh1KZqliP7719c5UDGZ0LWg",[841,843],{"title":36,"path":37,"stem":38,"description":842,"icon":39,"children":-1},"What happens between sending an event and getting allow, review or block back.",{"title":46,"path":47,"stem":48,"description":844,"icon":49,"children":-1},"From a decision to a report filed with your FIU.",1792169656546]