Scrip is built around six concepts: programs, assets, participants, events, rules, and a double-entry ledger. The table below summarizes each one, and the end-to-end example at the bottom shows how they connect.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.
| Concept | What it is | Guide |
|---|---|---|
| Program | Container for rules, assets, and participants | Programs |
| Asset | Unit of value: points, cashback, nights, credits | Assets |
| Participant | A user in your system, identified by your external_id | Participants |
| Event | A signal from your app that triggers rule evaluation | Events |
| Rule | A CEL condition and a list of actions | Rules |
| Ledger | Double-entry record of every balance change | Ledger |
Programs
A program is the top-level container. It holds your rules, links to your assets, and scopes your participants. Most teams create one program per use case: “Customer Loyalty,” “Referral Rewards,” “Driver Incentives.” Events are always sent to a specific program, and rules belong to exactly one program.Assets
An asset is the unit of value you’re tracking. Points, cashback dollars, nights stayed, referral credits. You configure how each asset behaves:- Inventory mode:
SIMPLEtracks a single aggregate balance.LOTtracks each credit individually with its own expiration and vesting dates, so points can expire in the order they were earned. - Issuance policy:
UNLIMITEDmints new value on every credit (no cap).PREFUNDEDdraws from a fixed program wallet, so credits fail when the wallet is empty. UsePREFUNDEDwhen you need to enforce a budget.
Participants
Participants are your users. You identify them with your ownexternal_id so they stay in sync with your application. Participants can be created explicitly or automatically on first event.
Each participant carries state that rules can read and write:
- Tags: Boolean flags like
VIPorFIRST_PURCHASE. - Counters: Numeric values like
lifetime_spendorpurchase_count. - Attributes: Key-value strings like
region: "US".
Events
Events are the inputs. Your application sends one whenever something happens that might affect a participant: a purchase, a signup, a referral, a cancellation.idempotency_key ensures exactly-once processing: if you retry the same event with the same key, you get back the original response instead of processing it again. Reusing a key with a different payload returns 409 Conflict.
Rules
A rule is a condition and a list of actions. The condition is a CEL expression (Common Expression Language, a lightweight expression syntax) evaluated against the event and the participant’s current state. When it returns true, the actions fire.stop_after_match: true on that rule to skip the remaining rules.
The Ledger
Every balance change is recorded as a journal entry with two sides: a debit and a credit. When a participant earns points, the credit goes to the participant and the corresponding debit comes from the program wallet. Nothing is ever mutated in place. This gives you a complete audit trail: you can trace any balance back to the event and rule that created it.End-to-End Example
Using the “Cashback on large purchases” rule from above, here’s what happens when a $105 purchase comes in:Your app sends an event
user_123 made a $105 purchase. You send it to Scrip with external_id: "user_123" and event_data: {type: "purchase", amount: 105.00}.The engine loads the participant
Scrip looks up the participant matching
user_123 and loads their current state: tags, counters, and attributes.Rules evaluate in order
The condition
event.type == 'purchase' && event.amount >= 100.0 is checked. 105 >= 100, so it matches.