> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scrip.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Simulate a rule

> Dry-run a rule against sample event data. No ledger changes occur.

Dry-runs a rule against sample data. Nothing persists: no balances move, no counters increment, no events are recorded.

The `event` field is required and should mirror a real event payload. As with real ingestion, numeric values whose magnitude exceeds 2^53 are rejected with `400 amount_precision_exceeded`; send very large values as strings.

Participant context comes from one of two mutually exclusive sources (supplying both returns a `400`):

* **`participant_id`**: loads a real participant's current state and ledger balances, so `participant.balance.<symbol>` conditions evaluate against actual values. Returns `404` if the participant doesn't exist. Still a dry run: nothing is locked or written.
* **`participant_state`**: caller-supplied mock state (`tags`, `counters`, `attributes`, optionally `tiers` and `balances`). Counter values may be JSON numbers or decimal strings; both are evaluated numerically.

With neither, the condition evaluates against empty defaults (counters `0`, no tags, attributes, tiers, or balances), and the response carries a `missing_participant_context` warning if the condition reads participant state. Balance comparisons never match without balances.

The response pairs the rule's metadata (`rule`) with the simulation outcome (`evaluation`): `matched`, `status` (`evaluated`, or `condition_failed` with a `reason`), and per-action `results` when matched. Result fields vary by action type; state projections (`current_value`, `would_add`, and similar) are included only when the action targets the event participant.

| Action type                                     | Result fields                                              |
| ----------------------------------------------- | ---------------------------------------------------------- |
| `CREDIT`, `DEBIT`, `HOLD`, `RELEASE`, `FORFEIT` | `amount`, `asset_symbol`, `description`                    |
| `COUNTER`                                       | `current_value`, `projected_value`, `value`, `description` |
| `TAG`                                           | `current_tags`, `would_add`, `description`                 |
| `UNTAG`                                         | `current_tags`, `would_remove`, `description`              |
| `SET_ATTRIBUTE`                                 | `current_value`, `would_change`, `description`             |
| `SET_TIER`                                      | `description`                                              |
| `SCHEDULE_EVENT`                                | `payload`, `description`                                   |
| `BROADCAST`                                     | `payload`, `description`                                   |

`VOID_HOLD` actions are not yet supported in simulation. `SCHEDULE_EVENT` and `BROADCAST` are not executed, but their `payload` templates are resolved, so a bad template surfaces here before the rule ever fires on a live event. Amount constraints match production: an asset action whose amount resolves to zero, negative, or beyond the precision-safe range fails in its result (`COUNTER` deltas may still be negative).

To check CEL syntax without an existing rule, use the [validate endpoint](/api-reference/rules/validate-a-cel-condition); to dry-run an unsaved rule, use [simulate a draft rule](/api-reference/rules/simulate-a-draft-rule).

<Note>
  For usage patterns and examples, see the [Writing Rules guide](/guides/writing-rules).
</Note>


## OpenAPI

````yaml POST /v1/rules/{id}/simulate
openapi: 3.0.3
info:
  contact:
    email: support@scrip.dev
    name: Scrip Support
    url: https://scrip.dev/support
  description: >-
    Universal Incentive Infrastructure API for managing loyalty programs,
    rewards, and participant balances.


    Scrip provides a complete backend for building incentive and loyalty
    programs. Core concepts:

    - **Programs**: Containers for incentive logic (e.g., "Q1 Sales Bonus",
    "Customer Loyalty")

    - **Assets**: The currency or points being tracked (e.g., "Bonus Points",
    "Cash Rewards")

    - **Participants**: Users who earn and spend assets (identified by
    external_id)

    - **Groups**: Collections of participants for team-based incentives

    - **Rules**: Automated reward logic triggered by events

    - **Events**: Actions that trigger rule evaluation (e.g., "purchase",
    "referral")


    Response formats:

    - **Collection endpoints** return: {"data": [...], "pagination":
    {"has_more": true, "next_cursor": "..."}}

    - **Single-resource endpoints** return the resource directly

    - **Errors** return: {"code": "...", "message": "...", "details": {...}} —
    `details` is an optional object, present on input errors only
  license:
    name: Proprietary
    url: https://scrip.dev/license
  termsOfService: https://scrip.dev/terms
  title: Scrip API
  version: '1.0'
servers:
  - url: https://api.scrip.dev
security: []
tags:
  - description: >-
      Manage incentive programs. Programs are the top-level container for all
      incentive logic.
    name: Programs
  - description: >-
      Manage asset types (currencies, points). Assets define what participants
      can earn and spend.
    name: Assets
  - description: >-
      Manage participants and their balances. Participants are identified by
      external_id from your system.
    name: Participants
  - description: Manage participant groups for team-based incentives.
    name: Groups
  - description: >-
      Manage automated reward rules. Rules define conditions and actions
      triggered by events.
    name: Rules
  - description: Ingest events that trigger rule evaluation and reward distribution.
    name: Events
  - description: Transfer assets between participants.
    name: Transfers
  - description: Access ledger summaries and program activity reports.
    name: Reporting
  - description: >-
      Redeem participant balances for rewards. Supports raw amount redemptions
      and catalog item redemptions.
    name: Redemptions
  - description: >-
      Manage the reward catalog. Create and manage redeemable items with
      inventory tracking.
    name: Rewards
  - description: >-
      Schedule and manage automated event dispatching. Automations generate
      events on cron schedules, at specific times, or by evaluating participant
      state.
    name: Automations
  - description: >-
      Manage tier types and levels within programs. Tiers define status
      hierarchies that participants progress through based on qualification
      rules.
    name: Tiers
  - description: Inspect double-entry ledger records for auditing and reconciliation.
    name: Journal Entries
  - description: >-
      Manage webhook endpoints and delivery logs. Webhooks notify your
      application of real-time events via HTTP POST with HMAC-SHA256 signatures.
    name: Webhooks
paths:
  /v1/rules/{id}/simulate:
    post:
      tags:
        - Rules
      summary: Simulate a rule
      description: Dry-run a rule against sample event data. No ledger changes occur.
      operationId: simulateRule
      parameters:
        - description: Rule ID
          in: path
          name: id
          required: true
          schema:
            format: uuid
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/handlers.SimulateRuleRequest'
        description: Sample event and optional participant state
        required: true
        x-originalParamName: request
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.SimulateRuleResponse'
          description: Simulation result
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrBadRequestResponse'
          description: 'Invalid request (code: validation_error | bad_request)'
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrUnauthorizedResponse'
          description: 'Missing or invalid credentials (code: unauthorized)'
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrForbiddenResponse'
          description: 'Insufficient permissions (code: forbidden)'
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrNotFoundResponse'
          description: 'Rule not found (code: not_found)'
        '415':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrUnsupportedMediaTypeResponse'
          description: 'Content-Type must be application/json (code: unsupported_media_type)'
        '500':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrInternalResponse'
          description: 'Internal server error (code: internal_error)'
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
components:
  schemas:
    handlers.SimulateRuleRequest:
      additionalProperties: false
      properties:
        event:
          description: >-
            Event is the sample event data to evaluate against the rule.

            Kept as raw JSON so numeric values can be precision-checked before
            the

            float64 decode (numbers above ±2^53 are rejected — SCR-323).
          example:
            amount: 75
            type: purchase
          type: object
        participant_id:
          description: >-
            ParticipantID optionally identifies a real participant whose current
            state

            (tags, counters, attributes, tiers — the same fields production rule

            evaluation sees) is loaded as the simulation's participant context.

            Mutually exclusive with participant_state. The simulation remains a

            dry run: no state is read with locks and nothing is written.
          example: 550e8400-e29b-41d4-a716-446655440000
          format: uuid
          type: string
        participant_state:
          additionalProperties: {}
          description: >-
            ParticipantState is optional simulated participant state (tags,
            counters, attributes).

            Conditions read it via the dot-access shorthand
            (participant.counter/tag/attribute.<name>,

            with safe defaults) or the get(participant.counters, ...) form,
            matching production evaluation.

            Counter values may be JSON numbers or decimal strings (the wire
            format returned by the

            participant state endpoints); both are evaluated numerically.

            Mutually exclusive with participant_id.
          example:
            attributes:
              region: US
            counters:
              purchase_count: 9
            tags:
              - vip
          type: object
      required:
        - event
      type: object
    handlers.SimulateRuleResponse:
      properties:
        evaluation:
          allOf:
            - $ref: '#/components/schemas/handlers.SimulateEvaluation'
          description: Evaluation contains the simulation results
        rule:
          allOf:
            - $ref: '#/components/schemas/handlers.SimulateRuleInfo'
          description: Rule contains metadata about the rule that was simulated
        warnings:
          description: >-
            Non-blocking advisories about the simulation context — e.g.

            missing_participant_context when the rule's condition reads
            participant

            state but the request supplied neither participant_id nor

            participant_state, so the condition evaluated against empty
            defaults.
          items:
            $ref: '#/components/schemas/models.RuleWarning'
          type: array
      type: object
    handlers.ErrBadRequestResponse:
      additionalProperties: false
      properties:
        code:
          description: Code is the machine-readable error code
          example: bad_request
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: >-
            Details provides optional structured error context (field errors,
            etc.)
        message:
          description: Message is the human-readable error description
          example: Invalid request parameters
          type: string
      type: object
    handlers.ErrUnauthorizedResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: unauthorized
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Missing or invalid credentials
          type: string
      type: object
    handlers.ErrForbiddenResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: forbidden
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Insufficient permissions for this action
          type: string
      type: object
    handlers.ErrNotFoundResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: not_found
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Resource not found
          type: string
      type: object
    handlers.ErrUnsupportedMediaTypeResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: unsupported_media_type
          type: string
        details:
          allOf:
            - $ref: '#/components/schemas/handlers.ErrorDetails'
          description: Details provides optional structured error context
        message:
          description: Message is the human-readable error description
          example: Content-Type must be application/json
          type: string
      type: object
    handlers.ErrInternalResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: internal_error
          type: string
        message:
          description: Message is the human-readable error description
          example: An internal error occurred
          type: string
      type: object
    handlers.SimulateEvaluation:
      properties:
        matched:
          description: Whether the condition evaluated to true
          example: true
          type: boolean
        reason:
          description: Error detail when status is "condition_failed"
          example: 'no such key: amount'
          type: string
        results:
          description: >-
            Per-action outcomes with resolved amounts, projected counter values,
            and asset symbols. Present only when matched is true.
          example:
            - action:
                amount: ${{ event.amount * 10 }}
                asset_id: 550e8400-e29b-41d4-a716-446655440002
                type: CREDIT
              result:
                amount: '750'
                asset_symbol: POINTS
                description: Credit 750 POINTS to participant
          items:
            type: object
          type: array
        status:
          description: >-
            "evaluated" on success, or "condition_failed" if the CEL expression
            errored
          example: evaluated
          type: string
      type: object
    handlers.SimulateRuleInfo:
      properties:
        condition:
          description: CEL expression that was evaluated
          example: event.type == 'purchase' && event.amount > 0
          type: string
        id:
          description: Unique identifier for the rule
          example: 550e8400-e29b-41d4-a716-446655440000
          format: uuid
          type: string
        name:
          description: Display name
          example: Purchase Reward
          type: string
        order:
          description: Evaluation sequence position
          example: 100
          type: integer
        stop_after_match:
          description: Whether this rule stops subsequent evaluation on match
          example: false
          type: boolean
      type: object
    models.RuleWarning:
      properties:
        code:
          description: >-
            Machine-readable warning category, e.g.
            RuleWarningCodeUnknownStateKey.
          example: unknown_state_key
          type: string
        key:
          description: The referenced key, as written in the condition.
          example: purchaseCnt
          type: string
        kind:
          description: >-
            State kind: StateKindCounter, StateKindTag, StateKindAttribute, or
            StateKindAlias.
          example: counter
          type: string
        message:
          description: >-
            Human-readable explanation (includes the suggestion when one
            exists).
          example: >-
            unknown counter "purchaseCnt" — no rule in this program writes it;
            did you mean "purchase_count"?
          type: string
        scope:
          description: >-
            State scope of the reference: StateScopeParticipant,
            StateScopeProgram, or StateScopeGroup.
          example: participant
          type: string
        suggestion:
          description: Closest known key, when a near-match exists. Empty otherwise.
          example: purchase_count
          type: string
      type: object
    handlers.ErrorDetails:
      description: >-
        Optional structured details about the error. Always a JSON object: a
        `fields` array for validation errors, or flat
        field/reason/expected/received properties for other input errors.
      properties:
        expected:
          description: Expected value or format (non-validation input errors)
          example: uuid
          type: string
        field:
          description: Field name that caused the error (non-validation input errors)
          example: asset_id
          type: string
        fields:
          description: >-
            Fields lists each offending input field on validation_error
            responses.
          items:
            $ref: '#/components/schemas/handlers.ErrorFieldDetail'
          type: array
        reason:
          description: Machine-readable reason code (non-validation input errors)
          example: invalid
          type: string
        received:
          description: Value that was received (non-validation input errors)
          example: not-a-uuid
          type: string
      type: object
    handlers.ErrorFieldDetail:
      description: >-
        A single field-level error: which input field failed, why, and (where
        known) the expected and received values.
      properties:
        expected:
          description: >-
            Expected value or format. Usually a string; for "one of" constraints
            it

            is an array of the allowed values.
        field:
          description: Field name that caused the error
          example: amount
          type: string
        message:
          description: Human-readable explanation (validation errors only)
          example: This field is required
          type: string
        reason:
          description: Machine-readable reason code
          example: required
          type: string
        received:
          description: Value that was received
          example: '-10.00'
          type: string
      type: object
  securitySchemes:
    ApiKeyAuth:
      description: API key passed in the X-API-Key header.
      in: header
      name: X-API-Key
      type: apiKey
    BearerAuth:
      description: Bearer token passed in the Authorization header (e.g. "Bearer sk_...").
      in: header
      name: Authorization
      type: apiKey

````