RequestRocketRequestRocketDocs
Control

Predicates

Match requests and responses so policy applies only to the calls you choose.

A predicate is a set of checks that decides whether a policy record applies. For example, a rule can deny requests whose method is DELETE and whose path starts with /admin.

Rules, meters, overrides, filters, alerts, and transforms share the request predicate fields. Filters and response transforms can also inspect the target response. Rules and filters can exist on credential and target scopes as well as proxies.

Rule editor on a saved proxy, Control tab, with path, method, header, query, and body predicate fields visible

Fields

A call must satisfy every predicate dimension you configure for the action to apply.

FieldIn the appWhat it checks
methodsHTTP MethodsThe HTTP method. Empty means every method.
pathRequest PathThe path after the proxy base URL, starting with /.
headersHeader ChecksA header name, and optionally its value.
queryQuery Parameter ChecksA query parameter name, and optionally its value.
bodyBody ChecksA field in the JSON request body, and optionally its value.
tokenToken ChecksA claim in the inbound credential's JWT, and optionally its value.
responseStatusResponse StatusThe HTTP status code of the target's response. Filters and response transforms only.
responseHeadersResponse Header ChecksA header name on the target's response, and optionally its value. Filters and response transforms only.
responseBodyResponse Body ChecksA field in the JSON response body, and optionally its value. Filters and response transforms only.
variablesVariablesNames pulled from the call and reused inside patterns.

Filters call the path field requestPath. The response fields check the target's answer, so a rule, meter, override, or request transform, which runs before the target answers, cannot use them.

Priority is not a predicate but it does determine which predicates are evaluated first (relevant for request and response transforms that only trigger on the first evaluated action).

How predicates work with each action

A predicate only answers whether a call matches. What a match does depends on the action it is attached to, and on the effect or default set on that action.

ActionWhat a match does
RuleApplies the rule's effect, allow or deny. Every matching rule is considered, and one matching deny denies the call whatever the priority. When no rule matches, or there are no rules, the default rule effect on the proxy, MCP server, inbound credential, or target decides. A default of deny means a call needs a matching allow rule to get through.
MeterWith mode all the predicate is ignored and every call counts. With mode conditional, effect include counts calls that match and exclude counts calls that do not.
LimitA limit has no predicate of its own. It sits on a meter, so the meter's predicate decides which calls count toward the window.
OverrideMode and effect work as they do on a meter. Every applicable override is applied, and on a clash the higher priority wins.
Request transform and response transformMode and effect work as they do on a meter, but only the highest-priority applicable transform runs. A response transform can also use the response fields.
FilterThe predicate decides whether the filter runs on the response. Inside it, each operation's jsonPath picks fields to retain or destroy, and defaultFilterOperation decides what happens to every field no operation picks.
AlertMode and effect work as they do on a meter. An alert attached to another action fires on the calls that action matches.

The include and exclude effects are the reverse of one another. exclude with a predicate is the same as include with that predicate negated, so use whichever reads better.

Two common predicates

Match an admin path

This predicate matches any path that begins with /admin/. Attach it to a deny rule to block that path.

{
  "path": {
    "path": { "pattern": "^/admin/" },
    "presence": "must_exist"
  }
}

Require a tenant header

This predicate matches when x-tenant-id exists and has a non-empty value.

{
  "headers": [
    {
      "name": { "pattern": "^x-tenant-id$", "flags": "i" },
      "value": { "pattern": ".+" },
      "presence": "must_exist"
    }
  ]
}

In a Core MCP tool call, pass these objects in the tool's path or headers argument. In the Core API, put the same object in the JSON request body. The app exposes the same fields in the policy editor.

Patterns are regular expressions

The name, value, path, field, and claim fields are regular expressions. They use JavaScript regex syntax. Each one is an object with a pattern and optional flags.

{ "pattern": "^/orders/\\d+$", "flags": "i" }

Keep these points in mind when you write one.

  • A pattern is not anchored. /orders also matches /archive/orders/42. Start with ^ and end with $ to match the whole value.

  • A dot matches any character. Write \. for a literal dot. The path ^custom_metadata\.region$ matches one claim. custom_metadata.region also matches custom_metadata_region.

  • Flags are JavaScript flags. Any flag the JavaScript RegExp constructor accepts is passed through. Leave flags empty for none. An invalid flag, or a combination JavaScript rejects, makes the pattern never match.

    FlagNameEffect
    iIgnore caseLetters match in either case.
    mMultiline^ and $ match at each line break, not only at the start and end of the value.
    sDot allA dot also matches a newline.
    uUnicodeTreats the pattern and value as Unicode code points and enables \p{...} property escapes.
    vUnicode setsA stricter Unicode mode that adds set operations in character classes. Use it instead of u. The two cannot be combined.
    yStickyThe match must begin at the start of the value, as if the pattern started with ^.
    gGlobalAccepted, but has no effect on whether a check matches.
    dIndicesAccepted, but has no effect on whether a check matches.
  • Escape backslashes in JSON. In an API body, \d is written \\d. In the app, type it as \d.

  • A pattern that does not compile never matches. A Must Exist check on it fails, so test a new pattern before you rely on it.

Presence

Each check has a presence setting. The app shows Must Exist and Must Be Absent. The API values are must_exist and must_absent.

  • Must Exist passes when something matches the pattern.
  • Must Be Absent passes when nothing matches the pattern.

A check with a name and a value matches only when the same header, parameter, or field has both. A check with a name and no value matches when the name is present.

Headers and query parameters

The name pattern is tested against every header or parameter name. The value pattern, when set, is tested against the value of those that match the name. Header names can arrive in any case, so add the i flag to a name pattern such as ^x-tenant-id$.

Body and token paths

Body and token checks use dot notation. Each key is joined with a dot, and an array position is its number.

{ "data": { "items": [{ "sku": "A1" }] } }

In this body the paths are data, data.items, data.items.0, and data.items.0.sku. The pattern in jsonPath is tested against every one of them.

  • ^data\.items$ matches the array.
  • ^data\.items\.\d+\.sku$ matches the sku of each item.
  • matchField is a pattern for a key inside the node jsonPath found. When that node is an array, each object in it is checked.
  • matchValue is a pattern for the value of that key.

Token checks work the same way against the decoded claims. claim is the path, such as ^custom_metadata\.region$, and value is tested against the claim value as text. Token checks read the Bearer JWT on the call, which a JWT inbound credential has already verified. With no token, a Must Exist check fails and a Must Be Absent check passes.

Variables

A variable gives a call value a name, so a pattern can use it. Define it once on the record, then write {{name}} in any pattern field. Variables are shared by every check on that record.

{ "name": "tenant", "source": "jwtClaim", "key": "tenant" }
FieldMeaning
nameThe token to write between double braces. Use letters, digits, and underscores.
sourceWhere the value comes from.
keyWhich value to read from that source.

Sources

Source in the appAPI valuekey is
HeaderheadersA header name.
Query ParamparamsA query parameter name.
Request Body FieldbodyA dot-notation path into the JSON request body, such as data.userId.
JWT ClaimjwtClaimA dot-notation path into the inbound credential's claims, such as custom_metadata.region.
Static ValuestaticThe text itself.
Response HeaderresponseHeadersA header name on the target's response.
Response Body FieldresponseBodyA dot-notation path into the response body.
Response StatusresponseStatusNothing. The value is the status code.

The three response sources are for filters and response transforms. A rule, meter, override, or request transform runs before the target answers, so it has no response to read.

How a variable is substituted

RequestRocket replaces each {{name}} with the value before it compiles the regular expression.

  • A value from the call is matched literally. Characters such as ., *, +, ?, (, and | are escaped first. A claim of acme.corp becomes acme\.corp. It cannot widen the pattern.
  • A Static Value is not escaped. Regex characters in it keep their meaning, so a static value of admin|superuser matches either word.
  • Write the braces with no spaces. {{tenant}} is substituted. {{ tenant }} is not.
  • A name with no matching variable fails the check. The same happens when the variable's source is missing from the call, for example a header that was not sent.

That last point has a consequence for Must Be Absent. A check that cannot resolve a variable does not match, so it does not pass as absent either. When a rule depends on a claim or header, add a check that requires it to exist.

Example: keep a caller inside its own tenant

The path must start with the caller's tenant claim.

{
  "effect": "allow",
  "ruleActive": true,
  "priority": 10,
  "variables": [
    { "name": "tenant", "source": "jwtClaim", "key": "tenant" }
  ],
  "path": {
    "path": { "pattern": "^/tenants/{{tenant}}/" },
    "presence": "must_exist"
  }
}

For a caller whose tenant claim is acme.corp, the pattern becomes ^/tenants/acme\.corp/. The path /tenants/acme.corp/orders matches. /tenants/acmeXcorp/orders does not. A caller with no tenant claim does not match this rule.

Example: match one of several values

A Static Value keeps its regex meaning, so it can hold a list.

{
  "variables": [
    { "name": "roles", "source": "static", "key": "admin|superuser" }
  ],
  "token": [
    {
      "claim": { "pattern": "^role$" },
      "value": { "pattern": "^({{roles}})$" },
      "presence": "must_exist"
    }
  ]
}

The value pattern becomes ^(admin|superuser)$. The check passes when the role claim is exactly admin or superuser.

Rule editor Variables section expanded with one JWT Claim variable named tenant, and the Request Path pattern using the tenant token

Next

On this page