Skip to main content
A participant represents a user in your system. You identify participants with your own external IDs, and Scrip handles enrollment, balances, and state tracking.

Creating Participants

Explicitly via the API

If a participant with the same external_id already exists, the call upserts: it updates the existing participant instead of creating a duplicate.

Automatically on first event

When a program’s on_unknown_participant is set to CREATE (the default), participants are created the first time you send an event with an unrecognized external_id:
Scrip creates the participant, enrolls them in the program, and processes the event in one step. Set on_unknown_participant to REJECT if you want to require explicit creation before sending events. See Programs for details.

Auto-enrollment of existing participants

When an event targets a participant who exists but isn’t enrolled in the event’s program, Scrip automatically enrolls them. This applies across all identity paths (external_id, participant_id, recipient_id, recipient_external_id). Enrollment status is per-program and separate from the participant’s own status; an inactive enrollment is reactivated automatically by the next event. The on_unknown_participant setting only controls whether new participants are created. It does not affect enrollment of existing ones.

Profile Fields

Participants support optional profile fields for contact and display information: email, phone, first_name, last_name, and display_name. These are returned in all participant responses (create, update, get, list). Profile fields follow a three-state convention: The email field is validated on both create and update. Invalid addresses return a 400 error.

Identifiers

Participants have two IDs: To find a participant by your external ID:
Use the returned id for all subsequent API calls. The list endpoint returns identifiers, status, and profile fields. To get the full participant state in one call, use the detail endpoint:
The detail response includes balances, tags, counters, attributes, tiers, program_ids, and profile fields inline.

Status

A participant’s status controls what operations are allowed:

What’s allowed by status

This table covers rule actions, meaning what the rules engine can do when it processes an event for the participant. The direct balance API is gated separately: forfeit and void-hold requests are allowed on CLOSED participants so you can clean up balances after account closure (both remain blocked for SUSPENDED). See Balance Operations. Balance and counter actions are blocked because a suspended or closed participant should not accumulate value. Metadata actions (tags, attributes, tiers) are allowed because you still need to manage inactive accounts: tagging a participant with fraud_confirmed, setting attributes for audit trails, or adjusting tiers during a review period.

How this affects events

Events whose resolved actor or recipient is SUSPENDED or CLOSED are rejected before any rule runs. The event is accepted (202) and then recorded as a terminal FAILED event carrying error_code participant_suspended or participant_closed, with a matching event.failed webhook. Direct API management of tags, attributes, and tiers is not gated.
Idempotent replays are unaffected: retrying an event that was accepted while the participant was still ACTIVE returns the original event rather than a lifecycle rejection.

Balances

Check a participant’s current balances across all assets:
Balances are split by asset into three buckets: You can perform manual balance adjustments directly on a participant:
See Balance Operations for hold, release, forfeit, and other operations.

Transaction History

View the ledger entries for a participant:
Returns a chronological list of credits, debits, holds, and releases with journal entry details.

Time-Range Filters

The endpoint supports two independent time-range filters that can be combined (AND semantics): Entries without an originating event fall back to created_at for event_from/event_to filtering. You can also retrieve the events processed for a participant:

Participant State

Each participant carries state that rules can read and update: Tags are stored verbatim and matched case-sensitively. Pick one casing convention (these docs use lowercase) and use it in both TAG actions and conditions. Counters support high-precision numerics. See State Management for how to read, update, and use state in rules.