AbuseZero

Policies and rules

Build your own policy on top of a protection level, with rules, a risk threshold and a default result.

A policy decides allow or deny for every claim of every benefit that uses it. Protection levels are policies AbuseZero manages. Custom policies are yours: an optional protection level to build on, your own rules, a risk threshold and a default result.

Why it matters

Every product has its own idea of a fair claim. You may want to approve every user whose email and phone your app verified, or deny claims from networks you never serve. Custom policies let you write that down once, in AbuseZero, and change it at any time without touching your code.

Key capabilities

  • Validation on save. Unsupported conditions, values of the wrong type and out-of-range numbers are rejected when you save, so a broken rule never reaches a live evaluation.
  • Immutable versions. Each change creates a new policy version. Every evaluation records the version it ran under, and the full history stays readable.
  • Consistent conditions. Conditions mean exactly the same thing in live evaluations, previews, simulations and replays.
  • Shared policies. A change applies to every benefit that uses the policy, for future evaluations.
  • Safe concurrent edits. Updates carry a revision. An update against an older revision is refused with POLICY_CONFLICT.

Rule order

A policy reads from top to bottom:

  1. Your rules, in the order you list them. The first rule that matches decides the claim.
  2. The protection level you build on, if any, for the claims your rules don't decide.
  3. The risk threshold. A claim whose AbuseZero Risk Score reaches it is denied.
  4. The default result for everything else.

Allow and block list entries decide a matching claim outright, whatever the policy says. So does a benefit whose automation setting is deny, for claims with detected automation. See Allow and block lists and Bots and AI agents.

A custom policy definition
{
  "base": "balanced",
  "risk_threshold": 75,
  "default_result": "allow",
  "rules": [
    {
      "id": "allow_verified_first_claims",
      "name": "Verified users with no earlier claims",
      "result": "allow",
      "when": {
        "all": [
          { "signal": "email.verified", "operator": "eq", "value": true },
          { "signal": "phone.verified", "operator": "eq", "value": true },
          { "signal": "user.prior_claims", "operator": "eq", "value": 0 }
        ]
      }
    },
    {
      "id": "deny_disposable_on_anonymous_network",
      "name": "Disposable email on an anonymous network",
      "result": "deny",
      "when": {
        "all": [
          { "signal": "email.disposable", "operator": "eq", "value": true },
          { "signal": "network.anonymous", "operator": "eq", "value": true }
        ]
      }
    }
  ]
}
FieldRequiredMeaning
baseNolenient, balanced or strict. The protection level this policy builds on.
risk_thresholdNoA multiple of 5 from 5 to 100; any other value returns INVALID_FIELD. It compares against the AbuseZero Risk Score, which also moves in steps of 5. When you leave it out or send null, the base level's threshold applies, or AbuseZero's standard threshold if there is no base. Policy versions show it as null unless you set it yourself.
default_resultYesallow or deny, for claims nothing else decides.
rulesYesUp to 50 rules. Send an empty array for a policy with no rules of its own.

Rules

FieldMeaning
idYour ID for the rule, up to 64 characters, unique within the policy.
nameA name your team will recognize, up to 100 characters. It appears in the reason when you read the evaluation.
resultallow or deny.
whenOne condition, or a group: { "all": [...] } matches when every entry matches, { "any": [...] } when at least one does.

A group holds 1 to 10 entries. Groups can contain groups, up to two levels deep. A rule can have up to 10 conditions in total.

When one of your rules decides a claim, the evaluation's reason has the code custom_rule and the rule's id as rule. When you read the evaluation, the message names the rule:

"reason": { "code": "custom_rule", "message": "Your rule “Disposable email on an anonymous network” matched this claim.", "rule": "deny_disposable_on_anonymous_network" }

Conditions

Each condition compares one signal with a value:

{ "signal": "network.risk", "operator": "eq", "value": "high" }
OperatorMatches when
eq, neqThe signal equals, or doesn't equal, the value.
gt, gte, lt, lteThe signal is greater than, at least, less than or at most the value. Numeric signals only.
is_missingYou didn't send the input this signal needs. Takes no value.
is_unknownThe input was sent, but its value couldn't be determined. Takes no value.
is_unavailableThe assessment wasn't available for this evaluation. Takes no value.

A comparison never matches when the signal has no known value. To act on a missing or unavailable signal, add a condition with is_missing, is_unknown or is_unavailable.

Available signals

SignalTypeMeaning
email.verifiedbooleanYour app verified the email address.
email.disposablebooleanThe email address is disposable.
phone.verifiedbooleanYour app verified the phone number.
user.prior_claimswhole numberEarlier claims by this user.
email.prior_claimswhole numberEarlier claims with this email address.
device.prior_claimswhole numberEarlier claims from this device.
payment.prior_claimswhole numberEarlier claims with this payment method.
phone.prior_claimswhole numberEarlier claims with this phone number.
network.risklow, elevated or highThe network risk AbuseZero Network Intelligence assessed.
network.anonymousbooleanThe connection comes through an anonymous network.
network.repeat_attemptswhole numberRecent claim attempts from this network.
network.countryISO country codeThe country of the network, such as DE.
automation.detectedbooleanAbuseZero Automation Defense detected automated activity.
custom.<key>.prior_outcomeswhole numberEarlier claims with one of your custom identifiers.

GET /v1/policy-signals returns the built-in signals with their labels, types and allowed values, so your tools can build rule editors from it.

Versions

Each save creates a new version, and the policy's active_version moves to it. GET /v1/policies/{id}/versions lists every version, and GET /v1/policies/{id}/versions/{version} returns your definition as it was in that version. When an evaluation surprises you, open it, note its policy.version, and read that version.

Configuration

  • Create, update, duplicate and delete custom policies in the dashboard or through the Policies API. A policy can't be deleted while a benefit uses it. Reassign those benefits first.
  • Test before you save. Preview a claim, simulate a sequence of claims, or replay recent traffic against a new policy. See Test changes safely.
  • Attach the policy by setting a benefit's policy_key to the policy's key.

Programmatic access

Next steps

How is this guide?

Last updated on

On this page