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.
The Scrip API is a REST API. All requests and responses use JSON. The current version is v1.
If you’re new to Scrip, start with the Quickstart to create a program and process your first event, or read Core Concepts for an overview of the data model.
Authentication
Every request requires an API key in the Authorization header:
curl https://api.scrip.dev/v1/programs \
-H "Authorization: Bearer sk_your_api_key" \
-H "Content-Type: application/json"
Keys use the sk_ prefix and have full read/write access to all resources in your organization. You can also pass the key via the X-API-Key header. Create and manage keys from the Scrip dashboard.
See the Authentication page for details on key management and rate limits.
Conventions
| Convention | Detail |
|---|
| Property names | snake_case |
| IDs | UUIDs (550e8400-e29b-41d4-a716-446655440000) |
| Timestamps | RFC 3339 (2024-01-15T10:30:00Z) |
| Amounts | Strings to preserve decimal precision ("100.00") |
| Content type | application/json for all request and response bodies |
Idempotency
Events, balance operations (hold, release, forfeit), redemptions, reversals, and transfers accept an idempotency_key field. Use deterministic keys derived from your domain data (order-12345-completed), not random UUIDs.
All resource types behave the same way:
- Same key + same payload: returns the original response without reprocessing. Events return
202, all other operations return 200.
- Same key + different payload: returns
409 Conflict with code idempotency_conflict.
Keys are scoped to program_id. Payload comparison uses a SHA-256 hash of semantic fields. Cosmetic differences (JSON key order, trailing decimal zeros, whitespace) are normalized before hashing, so they will not trigger a conflict.
List endpoints return paginated results using cursor-based pagination:
{
"data": [
{ "id": "...", "name": "..." }
],
"pagination": {
"has_more": true,
"next_cursor": "eyJ..."
}
}
Pass cursor as a query parameter to fetch the next page. Use limit to control page size (default 50, max 200). Pagination is stable across concurrent modifications. Inserts and deletes between pages do not cause skipped or duplicated results.
Filtering, sorting, and search
Most list endpoints support query parameters for filtering and ordering results. Available parameters vary by endpoint and are documented in each endpoint’s parameter table.
Filtering
Filter by resource status or related IDs:
GET /v1/participants?status=ACTIVE&program_id=550e8400-...
GET /v1/events?status=COMPLETED&from=2025-01-01T00:00:00Z&to=2025-02-01T00:00:00Z
Time-range filters (from, to) accept RFC 3339 timestamps and filter on the resource’s creation time. from is required when to is provided, and from must be before to.
Sorting
Control result ordering with sort_by and sort_dir:
GET /v1/programs?sort_by=name&sort_dir=asc
GET /v1/events?sort_by=event_timestamp&sort_dir=desc
Each endpoint defines its own set of sortable fields (e.g., created_at, name, order). The default sort is typically created_at descending. Rules default to order ascending.
Search
Search uses case-insensitive partial matching. The searched field varies by resource:
| Resource | Searched fields |
|---|
| Participants | external_id |
| Programs, Rules | name |
| Assets | name and symbol |
GET /v1/participants?search=user_abc
GET /v1/rules?search=welcome
Errors
Error responses include a machine-readable code and a human-readable message:
{
"code": "not_found",
"message": "Program not found"
}
Some errors include a details object with field-level validation information:
{
"code": "validation_error",
"message": "Invalid request body",
"details": {
"name": "is required",
"key": "must be lowercase alphanumeric with hyphens"
}
}
Status codes
| Code | Meaning |
|---|
200 | Success |
201 | Resource created |
202 | Accepted for async processing (events) |
204 | Success, no content |
400 | Bad request or validation error |
401 | Unauthorized |
403 | Forbidden |
404 | Resource not found |
409 | Conflict (state violation, duplicate idempotency key, reversal exceeds remaining) |
422 | Business rule violation (insufficient funds, inactive resource) |
429 | Rate limit exceeded |
500 | Internal server error |
Error codes
The code field in error responses is a machine-readable string you can match on programmatically. Common codes by category:
Validation (400)
| Code | Description |
|---|
validation_error | One or more fields failed validation. Check details for field-level errors |
invalid_request | Request structure is invalid (e.g., mutually exclusive fields provided) |
invalid_amount | Amount is malformed, non-positive, or exceeds asset scale |
invalid_quantity | Quantity must be a positive integer |
asset_not_linked | Asset is not linked to the specified program |
reward_program_mismatch | Reward does not belong to the specified program |
Authentication & authorization (401 / 403)
| Code | Description |
|---|
unauthorized | Missing or invalid API key / JWT |
forbidden | Valid credentials but insufficient permissions for this action |
Not found (404)
| Code | Description |
|---|
not_found | The requested resource does not exist |
Conflict (409)
| Code | Description |
|---|
participant_inactive | Participant is SUSPENDED or CLOSED. Financial operations and counter updates are blocked for inactive participants |
idempotency_conflict | Idempotency key was already used with different parameters |
already_reversed | Redemption has already been fully reversed |
quantity_exceeds_remaining | Reversal quantity exceeds the remaining reversible units |
amount_exceeds_remaining | Reversal amount exceeds the remaining reversible amount |
max_total_exceeded | Reward’s global inventory limit reached |
max_per_participant_exceeded | Reward’s per-participant inventory limit reached |
program_archived | Program is archived and cannot be modified |
program_suspended | Program is suspended and cannot process transactions |
key_exists | A tier key or reward name already exists in this program |
Business rules (422)
| Code | Description |
|---|
insufficient_funds | Not enough balance for the requested operation |
asset_archived | Asset is archived and cannot be used in new operations |
program_inactive | Program is not active; events cannot be ingested |
participant_not_found | Participant does not exist and the program is configured to reject unknown participants |
recipient_not_found | Target participant not found or not enrolled in the program |
Rate limits
Requests are rate-limited per organization at 10 requests/second with burst to 30. All API keys in the same organization share one rate limit bucket. Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. When exceeded, the API returns 429 with a Retry-After header.
See Authentication for the full header reference.
Resources
| Resource | Prefix | Description |
|---|
| Programs | /v1/programs | Top-level containers for incentive logic |
| Assets | /v1/assets | Units of value (points, credits, cashback) |
| Participants | /v1/participants | Users who earn and spend |
| Groups | /v1/groups | Collections of participants |
| Rules | /v1/rules | CEL conditions and reward actions |
| Events | /v1/events | Signals that trigger rule evaluation |
| Tiers | /v1/programs/{id}/tiers | Status hierarchies for participants |
| Redemptions | /v1/participants/{id}/redemptions | Balance spend operations |
| Rewards | /v1/programs/{id}/rewards | Catalog items for redemption |
| Transfers | /v1/transfers | Value movement between participants |
| Automations | /v1/programs/{id}/automations | Scheduled event generation |
| Reporting | /v1/reports | Ledger summaries and activity |
| Logs | /v1/logs | Request history and usage metrics |
For a complete map of entities and their relationships, see the Data Model.