> ## 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.

# Introduction

> Base URL, request and response format, pagination, idempotency, and error conventions

The Scrip API is a REST API. All requests and responses use JSON. The current version is `v1`.

```bash theme={null}
https://api.scrip.dev/v1
```

<Note>
  If you're new to Scrip, start with the [Quickstart](/quickstart) to create a program and process your first event, or read [Core Concepts](/guides/core-concepts) for an overview of the data model.
</Note>

***

## Authentication

Every request requires an API key in the `Authorization` header:

```bash theme={null}
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](https://app.scrip.dev).

See the [Authentication](/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.

Balance operations (adjust, hold, release, forfeit, and void-hold, for both participants and groups) also accept the standard `Idempotency-Key` HTTP header as an alternative to the body field:

* **Header only:** the header value is used as the idempotency key.
* **Body only:** the body value is used (unchanged behavior).
* **Both, equal:** treated as one key.
* **Both, different:** `400` with reason `header_body_mismatch`. The API never silently picks one.

Header values must be 1–255 printable ASCII characters. Malformed values are rejected with a `400` whose `details` carry a reason: `empty`, `too_long`, `invalid_characters`, or `multiple_values`. On event ingestion endpoints, the idempotency key is carried only by the body field; a well-formed `Idempotency-Key` header is ignored there, though malformed values are still rejected.

Events use the idempotency key as the logical event identity:

* Reusing the same `program_id` + `idempotency_key` returns the same event identity without reprocessing, even if the payload differs.
* To correct or replace an event, send a new event with a new idempotency key.

Other idempotent operations compare the request payload:

* **Same key + same payload:** returns the original response without reprocessing.
* **Same key + different payload:** returns `409 Conflict` with code `idempotency_conflict`.

Keys are scoped to `program_id`. For operations that compare payloads, 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.

***

## Pagination

List endpoints return paginated results using cursor-based pagination:

```json theme={null}
{
  "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:

```bash theme={null}
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`:

```bash theme={null}
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` |

```bash theme={null}
GET /v1/participants?search=user_abc
GET /v1/rules?search=welcome
```

***

## Errors

Error responses include a machine-readable `code` and a human-readable `message`:

```json theme={null}
{
  "code": "not_found",
  "message": "Program not found"
}
```

Some errors include a `details` object with field-level validation information:

```json theme={null}
{
  "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                                                                                                                                                                               |
| `amount_precision_exceeded` | A numeric value in `event_data` exceeds the precision-safe range (magnitude above 2^53). Send very large values as strings                                                                                                              |
| `bad_request`               | Malformed request, including invalid `Idempotency-Key` header values (reason: `empty`, `too_long`, `invalid_characters`, `multiple_values`) or a header that conflicts with the body `idempotency_key` (reason: `header_body_mismatch`) |
| `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                                                                    |
| `tier_referenced_by_rules`     | Tier cannot be archived while `ACTIVE` or `SUSPENDED` rules reference its key. The error details list the referencing rules |

#### 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; accepted events fail during async processing                                                    |
| `participant_not_found` | Participant does not exist and the program is configured to reject unknown participants                                |
| `participant_suspended` | Event actor or recipient is `SUSPENDED` (or otherwise not active); the event is rejected at ingestion before rules run |
| `participant_closed`    | Event actor or recipient is `CLOSED`; the event is rejected at ingestion before rules run                              |
| `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](/authentication#rate-limits) for the full header reference.

***

## Resources

| Resource                                             | Prefix                              | Description                                    |
| ---------------------------------------------------- | ----------------------------------- | ---------------------------------------------- |
| [Programs](/api-reference/programs/overview)         | `/v1/programs`                      | Top-level containers for incentive logic       |
| [Assets](/api-reference/assets/overview)             | `/v1/assets`                        | Units of value (points, credits, cashback)     |
| [Participants](/api-reference/participants/overview) | `/v1/participants`                  | Users who earn and spend                       |
| [Groups](/api-reference/groups/overview)             | `/v1/groups`                        | Collections of participants                    |
| [Rules](/api-reference/rules/overview)               | `/v1/rules`                         | CEL conditions and reward actions              |
| [Events](/api-reference/events/overview)             | `/v1/events`                        | Signals that trigger rule evaluation           |
| [Tiers](/api-reference/tiers/overview)               | `/v1/programs/{id}/tiers`           | Status hierarchies for participants            |
| [Redemptions](/api-reference/redemptions/overview)   | `/v1/participants/{id}/redemptions` | Balance spend operations                       |
| [Rewards](/api-reference/rewards/overview)           | `/v1/programs/{id}/rewards`         | Catalog items for redemption                   |
| [Transfers](/api-reference/transfers/overview)       | `/v1/transfers`                     | Value movement between participants and groups |
| [Automations](/api-reference/automations/overview)   | `/v1/programs/{id}/automations`     | Scheduled event generation                     |
| [Reporting](/api-reference/reporting/overview)       | `/v1/reports`                       | Liability reports, summaries, and the journal  |

For a complete map of entities and their relationships, see the [Data Model](/api-reference/data-model).
