Skip to main content

Rule Simulation

Use the simulation endpoint to test a rule against sample data without creating real events or affecting balances. Simulation evaluates the rule’s CEL condition and returns what actions would fire, without executing them.
curl -X POST https://api.scrip.dev/v1/rules/{ruleId}/simulate \
  -H "Authorization: Bearer $SCRIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event": {
      "type": "purchase",
      "amount": 50.00,
      "category": "dining"
    },
    "participant_state": {
      "tags": ["active"],
      "counters": {"monthly_spend": 250},
      "attributes": {"tier": "gold"}
    }
  }'
The response shows whether the condition matched, the evaluated action amounts, and any errors in the CEL expression. Use this to iterate on conditions and amount formulas before activating a rule. Instead of mocking state with participant_state, you can pass participant_id to simulate against a real participant’s live tags, counters, attributes, tiers, identity fields, and ledger balances, the same context production evaluation sees. The two fields are mutually exclusive. If the rule’s condition reads participant state and you provide neither, the response includes a missing_participant_context warning and the condition evaluates against empty defaults (counters 0, no tags, attributes, or balances).
curl -X POST https://api.scrip.dev/v1/rules/{ruleId}/simulate \
  -H "Authorization: Bearer $SCRIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event": {"type": "purchase", "amount": 50.00},
    "participant_id": "550e8400-e29b-41d4-a716-446655440000"
  }'
Counter values in participant_state may be JSON numbers or decimal strings (the format the participant state endpoints return). Both are evaluated numerically, so you can paste a counters map from a real state read directly into a simulation request. Simulation enforces the same constraints as production execution: asset action amounts must resolve to positive values, and event numbers beyond the 2^53 precision boundary are rejected with 400 amount_precision_exceeded. Simulation does not execute SCHEDULE_EVENT or BROADCAST actions, but it does resolve their payload templates: the action result shows the resolved payload the action would emit, or an error naming the payload field when a template fails. Bad payload templates surface here instead of waiting for a live event.

Simulating a draft rule

To simulate a rule before saving it, use POST /v1/rules/simulate. It takes a program_id, a rule object with name, condition, and actions, and the same event, participant_id, and participant_state fields as saved-rule simulation; the draft is validated exactly like rule create but nothing is persisted.
curl -X POST https://api.scrip.dev/v1/rules/simulate \
  -H "Authorization: Bearer $SCRIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "program_id": "550e8400-e29b-41d4-a716-446655440001",
    "rule": {
      "name": "Dining bonus",
      "condition": "event.type == \"purchase\" && event.mcc == \"5812\"",
      "actions": [
        {
          "type": "CREDIT",
          "asset_id": "550e8400-e29b-41d4-a716-446655440002",
          "amount": "${{ round(event.amount * 0.05, 2) }}"
        }
      ]
    },
    "event": {"type": "purchase", "amount": 50.00, "mcc": "5812"}
  }'
A typical authoring loop: validate the expression, simulate the draft, save the rule, then simulate the saved rule against real participants.

Validation

To check an expression without creating a rule, use the validation endpoint:
curl -X POST https://api.scrip.dev/v1/rules/validate \
  -H "Authorization: Bearer $SCRIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "condition": "event.type == \"purchase\" && event.amount > 10.0"
  }'
This checks that the CEL expression compiles without evaluating it against any data. event.* field references like event.amount are not verified because events are schemaless. Participant fields, tier keys, and asset symbols are validated when you save a rule; pass program_id to this endpoint to run the same reference checks before saving.