Skip to content

Policies: how a rule becomes an action

Your policy turns reason codes into an action. Your fraud team owns the rules, the limits, the queues and the messages, per journey and market, and every version is kept, so any decision can be traced to the rule that applied at the time.

Names and fields are illustrative and agreed in the sandbox before any contract.

On this page

How a policy decides

  1. Rules read events and reason codes.

    A rule names the events it applies to and a condition on the session’s signals, so it always says why it fired. There is no threshold on a score to explain later.

  2. The strictest action wins.

    Every matching rule is recorded with the decision, and the action is the strictest of them: allow, warn, step up, cool off, hold, block. A warning never hides a hold.

  3. Per journey and market.

    A retail payment in India and a merchant payout in Singapore run different policies, with each market’s cool-off and limits. One SDK, one decision shape, your rules.

  4. Versioned.

    A change is a new version, and each decision names the version that made it. You can show which rule applied, to whom, and when it changed.

A policy file

The retail policy, version 14: eight rules and a default. It is the policy behind every decision on this site: the emulator blocked at sign-up, the face check on a new phone, the new payee held to ₹10,000 for 12 hours, the coached payment held and queued for a call back.

The policy

retail.yaml

# retail.yaml · version 14
# Every matching rule is recorded.
# The strictest action wins.

- id: block_emulator
  on: any
  when: device.emulator or device.tampered
  then: block
  message: session_unverified

- id: hold_scam_pattern
  on: [payee.add, payment.initiate]
  when: payee.mule_linked or (call.active and screen.shared)
  then: hold
  queue: scam-callback
  message: payment_paused_callback

- id: step_up_takeover
  on: [login.attempt, device.change, payee.add, payment.initiate]
  when: sim.moved or behaviour.drift
  then: step_up
  message: face_check

- id: step_up_remote_access
  on: [signup.start, login.attempt, device.change]
  when: screen.shared or remote.access
  then: step_up
  message: screen_share_stop

- id: step_up_number_unverified
  on: [signup.start, login.attempt, device.change]
  when: not number.verified
  then: step_up
  message: code_fallback

- id: cool_off_new_device
  on: [login.attempt, payee.add, payment.initiate]
  when: device.new
  then: cool_off
  hours: 12
  message: new_device_limit

- id: cool_off_rebind
  on: [device.change]
  when: always
  then: cool_off
  hours: 12
  message: rebind_limit

- id: warn_call
  on: [payee.add, payment.initiate]
  when: call.active
  then: warn
  message: call_warning

- id: default
  then: allow

What a condition names

A condition names a signal the SDK reads. When the rule fires, the signal is recorded as its reason code, so the rule and the reason are one record. The names below are the ones the file above uses.

Signals a condition can name, the code each is recorded as, and the module that reads it
SignalRecorded asRead by
device.emulatorEMULATORDevice intelligence
device.tamperedDEVICE_TAMPEREDDevice intelligence
screen.sharedSCREEN_SHAREDDevice intelligence
remote.accessREMOTE_ACCESSDevice intelligence
device.newNEW_DEVICESIM and device binding
sim.movedSIM_MOVEDSIM and device binding
number.verifiedNUMBER_VERIFIEDSilent network verification
behaviour.driftBEHAVIOUR_DRIFTBehavioural biometrics
call.activeACTIVE_CALLScam signals
payee.mule_linkedPAYEE_MULE_LINKEDPayee and mule graph

Versions

A change is a new version, and the version number travels with every decision it makes. Version 14 made two changes to version 13: coached payments go to the call-back queue, with the message the customer reads named in the rule, and a new device is limited for 12 hours instead of 24.

Version 13 to 14

retail.yaml

--- retail.yaml · version 13
+++ retail.yaml · version 14
 - id: hold_scam_pattern
   on: [payee.add, payment.initiate]
   when: payee.mule_linked
         or (call.active and screen.shared)
   then: hold
-  queue: fraud-review
+  queue: scam-callback
+  message: payment_paused_callback

 - id: cool_off_new_device
   on: [login.attempt, payee.add, payment.initiate]
   when: device.new
   then: cool_off
-  hours: 24
+  hours: 12
   message: new_device_limit

Because the decision object carries policy.version, a decision made under version 13 still reads as one: the 24-hour limit it applied is the limit that was in force, not an error.

Messages and queues

A rule can name the message the customer sees and the queue a person works. Messages are written for customers, not analysts: what happened to the money and what happens next. Queues are the names your FRM or case manager already uses; DeepID opens nothing of its own.

The messages a rule can name, with the action each belongs to
KeyActionThe customer reads
signup_verifiedallowYou’re verified. No code was needed.
login_okallowWelcome back. Nothing to type.
payee_addedallowR. Sharma is now one of your payees.
payment_sentallowPayment sent.
call_warningwarnIf someone on a call asked you to make this payment, stop. Banks, police and courts never ask you to move money to keep it safe.
first_payee_warningwarnThis payee is new to you. Check the name before you send.
face_checkstep_upConfirm it’s you with a quick face check.
screen_share_stopstep_upSomeone may be able to see your screen. Stop sharing it, then confirm it’s you.
code_fallbackstep_upWe couldn’t confirm your number with your network. Enter the code we’ve sent by SMS.
new_device_limitcool_offYou can send up to ₹10,000 from this phone now. You get the full limit in 12 hours.
new_payee_limitcool_offYou can send up to ₹10,000 to this payee now. You get the full limit in 12 hours.
rebind_limitcool_offYour new phone is set up. You can send up to ₹10,000 now, and the full limit in 12 hours.
payment_paused_callbackholdPayment paused. Your money hasn’t left your account. We’ll call you on +91 •••• 3210.
payee_paused_callbackholdPayee not added yet. We’ll call you on +91 •••• 3210 before anything changes.
session_unverifiedblockWe couldn’t verify this session. Your money is safe.

Map any key to your own copy and languages. Whatever is shown is logged with the decision, as the decision object page describes.

Journeys

The same policy sets the checks at each step of a journey, their order and their fallbacks: which login route runs first, when a face check steps in, how long a cool-off lasts in each market. The journey builder changes them without an app release, and each change is a new version of the policy the decision names.

Wire one moment in the sandbox, before any contract.

Sign-up or login end to end, with the decision back in the app and as an event, so your engineers see the shape of it before anyone signs anything.