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

# Create a tier

> Creates a new tier with levels within a program.

Creates a new tier within a program. A tier is a ranked progression track where participants hold exactly one level at a time.

Every tier needs a unique `key` and at least one level. Each level has its own `key` and a `rank` that sets its position in the hierarchy (higher rank = higher tier). Both the tier `key` and level `key` are immutable after creation. Keys must be lowercase alphanumeric with underscores, starting with a letter (pattern: `^[a-z][a-z0-9_]*$`).

Each level can also include `color` (hex code for UI display), `icon_url`, and a freeform `benefits` object. Tiers cannot be created under an archived program.

### Lifecycle

The `lifecycle` object controls how the tier behaves over time. Omit it to create a rules-only tier where changes are driven entirely by `SET_TIER` rule actions or direct API calls.

When present, `lifecycle` has five parts: `retention` (periodic re-evaluation or activity-based expiry), `qualification_period` (the evaluation cycle for period-based retention), `status_validity` (extends a status grant past period end), `downgrade_policy` (what happens when qualification lapses; defaults to `DROP_TO_QUALIFYING`), and `counters` (whether qualifying counters reset or carry over excess at period end). The [Tiers guide](/guides/tiers#retention-modes) covers each object's fields and behavior.

### Qualification

Each level can define `qualification` criteria for counter-based auto-advancement. After rules fire for an event, Scrip evaluates each level's thresholds and upgrades the participant to the highest level they qualify for.

Set `mode` to `ALL` (every criterion must pass) or `ANY` (at least one). Each criterion checks a counter key against a `threshold` using an `operator`: `>=`, `>`, `==`, `<=`, or `<`. `threshold` defaults to `0` when omitted, so set it explicitly for a meaningful criterion.

Auto-qualification only upgrades. Downgrades happen through the lifecycle system at period end or timer expiration.

### Benefits

`benefits` is a freeform JSON object on each level. Scrip stores it and returns it with the participant's tier state. Use it to drive behavior in your application: a `points_multiplier`, `free_shipping` flag, or `discount_percent`. Scrip does not interpret the benefits payload. It is a data contract between your tier configuration and your application.

<Note>
  For full examples, lifecycle walkthroughs, and tier state in CEL expressions, see the [Tiers guide](/guides/tiers).
</Note>


## OpenAPI

````yaml POST /v1/programs/{programId}/tiers
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/programs/{programId}/tiers:
    post:
      tags:
        - Tiers
      summary: Create a tier
      description: Creates a new tier with levels within a program.
      operationId: createTier
      parameters:
        - description: Program ID
          in: path
          name: programId
          required: true
          schema:
            format: uuid
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/handlers.CreateTierRequest'
        description: Tier definition with at least one level
        required: true
        x-originalParamName: request
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.TierResponse'
          description: Tier created
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrBadRequestResponse'
          description: 'Validation failed (code: validation_error | bad_request)'
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrUnauthorizedResponse'
          description: 'Missing or invalid credentials (code: unauthorized)'
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrNotFoundResponse'
          description: 'Program not found (code: not_found)'
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/handlers.ErrConflictResponse'
          description: >-
            Key already exists in program or program is archived (code:
            key_exists | program_archived)
        '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.CreateTierRequest:
      additionalProperties: false
      properties:
        display_name:
          description: Human-readable name shown in dashboards and reports
          example: Loyalty Status
          maxLength: 255
          type: string
        key:
          description: >-
            Unique identifier for this tier within the program (immutable after
            creation, lowercase alphanumeric + underscores)
          example: status
          maxLength: 100
          minLength: 1
          pattern: ^[a-z][a-z0-9_]*$
          type: string
        levels:
          description: Ordered set of levels within this tier (at least one required)
          items:
            $ref: '#/components/schemas/handlers.CreateTierLevelInput'
          minItems: 1
          type: array
        lifecycle:
          allOf:
            - $ref: '#/components/schemas/handlers.TierLifecycle'
          description: >-
            Controls how tiers behave over time: retention mode, qualification
            period, downgrade policy, and counter rollover. Omit for rules-only
            mode.
      required:
        - key
        - levels
      type: object
    handlers.TierResponse:
      description: A tier definition with its levels, lifecycle configuration, and metadata
      properties:
        archived_at:
          description: >-
            When the tier was archived (RFC 3339); absent while the tier is
            ACTIVE
          example: '2024-03-01T00:00:00Z'
          format: date-time
          type: string
        created_at:
          description: When this tier was created (RFC 3339)
          example: '2024-01-15T10:30:00Z'
          format: date-time
          type: string
        display_name:
          description: Human-readable name
          example: Loyalty Status
          type: string
        id:
          description: Unique identifier for this tier
          example: 550e8400-e29b-41d4-a716-446655440000
          format: uuid
          type: string
        key:
          description: Tier key used in API calls and rule actions
          example: status
          type: string
        levels:
          description: Ordered list of levels within this tier
          items:
            $ref: '#/components/schemas/handlers.TierLevelResponse'
          type: array
        lifecycle:
          allOf:
            - $ref: '#/components/schemas/handlers.TierLifecycle'
          description: >-
            Lifecycle configuration (retention mode, qualification period,
            downgrade policy, counter rollover)
        program_id:
          description: Program this tier belongs to
          example: 550e8400-e29b-41d4-a716-446655440001
          format: uuid
          type: string
        status:
          description: >-
            Lifecycle status: ACTIVE, or ARCHIVED once the tier has been
            archived
          example: ACTIVE
          type: string
        updated_at:
          description: When this tier was last modified (RFC 3339)
          example: '2024-01-15T10:30:00Z'
          format: date-time
          type: string
      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.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.ErrConflictResponse:
      properties:
        code:
          description: Code is the machine-readable error code
          example: conflict
          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 already exists or state conflict
          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.CreateTierLevelInput:
      additionalProperties: false
      properties:
        benefits:
          description: >-
            Arbitrary key-value payload granted when a participant reaches this
            level
          type: object
        color:
          description: Hex color code for UI display
          example: '#FFD700'
          maxLength: 50
          type: string
        display_name:
          description: Human-readable name for this level
          example: Gold
          maxLength: 255
          type: string
        icon_url:
          description: URL to an icon image for this level
          example: https://example.com/icons/gold.png
          maxLength: 500
          type: string
        key:
          description: >-
            Unique identifier for this level within the tier (immutable after
            creation, lowercase alphanumeric + underscores)
          example: gold
          maxLength: 100
          minLength: 1
          pattern: ^[a-z][a-z0-9_]*$
          type: string
        qualification:
          allOf:
            - $ref: '#/components/schemas/handlers.TierQualification'
          description: Counter-based criteria for automatic advancement to this level
        rank:
          description: >-
            Position in the progression order (higher = better, must be unique
            within the tier)
          example: 2
          minimum: 1
          type: integer
      required:
        - key
        - rank
      type: object
    handlers.TierLifecycle:
      description: >-
        Time-based tier automation: retention, qualification period, downgrade
        policy, and counter rollover.
      properties:
        counters:
          allOf:
            - $ref: '#/components/schemas/handlers.TierCounters'
          description: Qualifying-counter handling at period boundaries.
        downgrade_policy:
          allOf:
            - $ref: '#/components/schemas/handlers.TierDowngradePolicy'
          description: Target level when a participant no longer qualifies.
        qualification_period:
          allOf:
            - $ref: '#/components/schemas/handlers.TierQualificationPeriod'
          description: Period boundary used by PERIOD_BASED retention.
        retention:
          allOf:
            - $ref: '#/components/schemas/handlers.TierRetention'
          description: How tier status is retained or lost over time.
        status_validity:
          allOf:
            - $ref: '#/components/schemas/handlers.TierStatusValidity'
          description: How long a status grant remains valid past the period end.
      type: object
    handlers.TierLevelResponse:
      description: >-
        A level within a tier, including its rank, qualification criteria, and
        benefits
      properties:
        benefits:
          description: Key-value payload granted when a participant reaches this level
          type: object
        color:
          description: Hex color code for UI display
          example: '#FFD700'
          type: string
        created_at:
          description: When this level was created (RFC 3339)
          example: '2024-01-15T10:30:00Z'
          format: date-time
          type: string
        display_name:
          description: Human-readable name
          example: Gold
          type: string
        icon_url:
          description: URL to an icon image for this level
          example: https://example.com/icons/gold.png
          type: string
        id:
          description: Unique identifier for this level
          example: 550e8400-e29b-41d4-a716-446655440002
          format: uuid
          type: string
        key:
          description: Level key used in API calls and rule actions
          example: gold
          type: string
        qualification:
          allOf:
            - $ref: '#/components/schemas/handlers.TierQualification'
          description: Counter-based criteria for automatic advancement to this level
        rank:
          description: Position in the progression order (higher = better)
          example: 2
          type: integer
        updated_at:
          description: When this level was last modified (RFC 3339)
          example: '2024-01-15T10:30:00Z'
          format: date-time
          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.TierQualification:
      description: Counter-threshold criteria for automatic advancement into a tier level.
      properties:
        criteria:
          description: >-
            Non-empty list of counter-threshold criteria. Required for a
            non-empty

            qualification; omitted for the "{}" clear value.
          items:
            $ref: '#/components/schemas/handlers.TierQualificationCriterion'
          minItems: 1
          type: array
        mode:
          description: >-
            Match mode. ANY matches when any criterion is met; ALL requires
            every one.

            Required for a non-empty qualification; omitted for the "{}" clear
            value.
          enum:
            - ANY
            - ALL
          example: ALL
          type: string
      type: object
    handlers.TierCounters:
      description: Qualifying-counter handling at period boundaries.
      properties:
        qualifying:
          description: Counter keys that count toward qualification.
          items:
            type: string
          type: array
        rollover:
          description: >-
            Rollover mode at period end. NONE resets counters to 0; EXCESS
            carries

            the amount above the qualifying threshold into the next period.
          enum:
            - NONE
            - EXCESS
          example: EXCESS
          type: string
      type: object
    handlers.TierDowngradePolicy:
      description: Target level when a participant no longer qualifies.
      properties:
        grace_days:
          description: >-
            Days to defer a downgrade; the current level is held until grace
            end.
          example: 30
          type: integer
        min_level:
          description: Level key the participant is never downgraded below.
          example: silver
          type: string
        mode:
          description: >-
            Downgrade mode. DROP_TO_QUALIFYING drops to the highest
            still-qualifying

            level; DROP_ONE drops one rank; HOLD keeps the current level.
          enum:
            - DROP_TO_QUALIFYING
            - DROP_ONE
            - HOLD
          example: DROP_ONE
          type: string
      required:
        - mode
      type: object
    handlers.TierQualificationPeriod:
      description: Period boundary used by PERIOD_BASED retention.
      properties:
        start_day:
          description: Day the period starts (1-31). Defaults to 1.
          example: 1
          type: integer
        start_month:
          description: Month the period starts (1-12). Required when type is FIXED_YEAR.
          example: 2
          type: integer
        type:
          description: Period type.
          enum:
            - CALENDAR_YEAR
            - FIXED_YEAR
            - NONE
          example: FIXED_YEAR
          type: string
      required:
        - type
      type: object
    handlers.TierRetention:
      description: How a participant keeps or loses tier status over time.
      properties:
        duration:
          description: >-
            Duration string with h/d/w units. Required when mode is
            ACTIVITY_REFRESH;

            ignored for PERIOD_BASED. Examples: "90d", "1w", or "2160h".
          example: 90d
          type: string
        mode:
          description: >-
            Retention mode. PERIOD_BASED re-evaluates at period end;
            ACTIVITY_REFRESH

            extends expiry on qualifying activity.
          enum:
            - PERIOD_BASED
            - ACTIVITY_REFRESH
          example: ACTIVITY_REFRESH
          type: string
      required:
        - mode
      type: object
    handlers.TierStatusValidity:
      description: How long a status grant remains valid past the period end.
      properties:
        extend_months:
          description: Months to extend status past period end. 0 = expires at period end.
          example: 1
          type: integer
      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
    handlers.TierQualificationCriterion:
      description: A single counter-threshold comparison.
      properties:
        counter:
          description: Counter key compared against the threshold.
          example: nights
          type: string
        operator:
          description: Comparison operator.
          enum:
            - '>='
            - '>'
            - '=='
            - <=
            - <
          example: '>='
          type: string
        threshold:
          description: Threshold value. Must be >= 0. Defaults to 0 when omitted.
          example: 25
          type: number
      required:
        - counter
        - operator
      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

````