Skip to main content

Use state in OPA rules

OPA rules can compare a generated answer with the state your application supplied. Rego reads the answer at input.output and the state snapshot at input.state.

Use this for calculations, relationships with generated values or rules that benefit from Rego's richer logic. For a small set of choices whose availability depends on known state, schema conditions can enforce the restriction directly during generation.

Define the output, facts and rule​

This example approves a duplicate-charge refund only when the order is paid and its amount is within the account's refund limit. Review remains an allowed fallback.

Save the three files:

state-policy.schema.json
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"approve",
"review"
],
"description": "Approve a substantiated duplicate charge when permitted; otherwise choose review."
},
"reason": {
"type": "string",
"enum": [
"duplicate_charge",
"manual_review"
],
"description": "The reason for the decision."
}
},
"required": [
"action",
"reason"
],
"additionalProperties": false,
"if": {
"properties": {
"action": {
"const": "approve"
}
},
"required": [
"action"
]
},
"then": {
"properties": {
"reason": {
"const": "duplicate_charge"
}
}
},
"else": {
"properties": {
"reason": {
"const": "manual_review"
}
}
}
}
refund-eligibility.state.json
{
"order": {
"paid": true,
"amount": 25
},
"refund_limit": 50
}
package refund

default allow := false

allow if {
input.output.action == "review"
}

allow if {
input.output.action == "approve"
input.state.order.paid == true
is_number(input.state.order.amount)
is_number(input.state.refund_limit)
input.state.order.amount <= input.state.refund_limit
}

The schema constrains the output shape and the relationship between action and reason. The Rego rule separately enforces the relationship with state. It has no schema eligibility extension, so the two approaches can be understood independently.

default allow := false denies answers unless an allow rule succeeds. The first rule permits review. The second permits approval only when the required facts are present and satisfy the comparisons. Missing state or nonnumeric amounts cannot satisfy the approval rule.

Send the policy and state​

Before you run this example

Call https://api.blatent.ai from your server. Set your API key in the same terminal where you run the example:

export BLATENT_API_KEY='YOUR_SERVICE_KEY'

Python requires Python 3.10+ and HTTPX:

python -m pip install "httpx>=0.28,<1"

TypeScript requires Node.js 24+ and uses its built-in fetch. The cURL examples require curl and jq.

Save the displayed files and the selected client in one directory. Run the client there with python example.py, node example.ts or bash example.sh. Downloads use the example's name in place of example.

import json
import os
from pathlib import Path
import httpx

request = {
"input": "This is a substantiated duplicate charge. Approve the refund.",
"policy": {
"engine": "opa",
"entrypoint": "data.refund.allow",
"modules": {
"state-refund.rego": Path("state-refund.rego").read_text(encoding="utf-8"),
},
},
"policy_max_retries": 8,
"schema": json.loads(Path("state-policy.schema.json").read_text(encoding="utf-8")),
"state": json.loads(Path("refund-eligibility.state.json").read_text(encoding="utf-8")),
}
with httpx.Client(
base_url="https://api.blatent.ai",
headers={"Authorization": f"Bearer {os.environ['BLATENT_API_KEY']}"},
timeout=195,
) as client:
response = client.post("/v1/resolve", json=request)
response.raise_for_status()
print(json.dumps(response.json()["output"]))

Illustrative output: {"action":"approve","reason":"duplicate_charge"}.

If order.paid is false, the amount exceeds the limit, or state is omitted, the policy denies approval and allows review. A successful response must satisfy both the schema and policy. The service can search for an alternative within the configured budget; allowing a fallback does not guarantee it will find one. If that budget is exhausted, it returns 422 POLICY_SEARCH_EXHAUSTED.

Reference the right context​

Request valueRego path
state.order.paidinput.state.order.paid
state.refund_limitinput.state.refund_limit
Generated actioninput.output.action
Original request inputinput.input
Optional parametersinput.parameters
Application-supplied user contextinput.user_context

The state snapshot belongs to this request and is used for its policy checks. A schema or policy registered for reuse does not retain the previous request's state. Omitted optional context is absent from the policy input.

You may also combine schema eligibility with OPA: the schema narrows known choices, while Rego enforces additional relationships. OPA policies explains enforcement, and search budgets and feedback covers recovery settings. For permission claims, see permission context.