Create Tier

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…

Create Tier

Creates a new tier in DRAFT status for a loyalty program. The tier enters a maker-checker approval workflow: submit it with Submit Tier for Approval and publish it with Approve or Reject Tier before it becomes ACTIVE. A program can have up to 50 tiers and only one in-progress DRAFT at a time.

Example request

curl -X POST "https://eu.intouch.capillarytech.com/v3/tiers" \
  -H "Authorization: Basic <base64-encoded-credentials>" \
  -H "Content-Type: application/json" \
  -d '{
    "programId": 973,
    "name": "Platinum",
    "description": "Premium tier for top spenders",
    "color": "#E5E4E2",
    "eligibility": {
      "kpiType": "CURRENT_POINTS",
      "threshold": 75000,
      "upgradeType": "LAZY"
    },
    "validity": {
      "periodType": "SLAB_UPGRADE",
      "periodValue": 12,
      "unit": "NUM_MONTHS"
    }
  }'

Prerequisites

  • Authentication: Basic auth or OAuth token with loyalty program management permissions.
  • The program must have SLAB_UPGRADE and SLAB_DOWNGRADE strategies configured. If either is missing, configure them with the program-level Tier Advanced Settings endpoint (POST /programs/{programId}/updateTierAdvancedSettings) before creating tiers.

Header information

HeaderRequiredDescription
Idempotency-KeyOptionalUnique key to safely retry the request without creating duplicate tiers.

Body parameters

API quick reference

Tier
├── programId (integer)
├── name (string)
├── description (string)
├── color (string)
├── eligibility
│   ├── kpiType (enum)
│   ├── threshold (number)
│   ├── upgradeType (enum)
│   ├── expressionRelation (enum)
│   └── conditions[]
│       ├── type (enum)
│       ├── value (string)
│       ├── trackerName (string)
│       ├── trackerId (integer)
│       └── trackerCondition (integer)
└── validity
    ├── periodType (enum)
    ├── periodValue (integer)
    ├── unit (string)
    ├── startDate (string)
    ├── isFixedTypeWithoutYear (boolean)
    ├── renewalWindowType (enum)
    ├── computationWindowStartValue (integer)
    ├── computationWindowEndValue (integer)
    ├── minimumDuration (integer)
    └── renewal
        ├── criteriaType (string)
        ├── downgradeTo (enum)
        ├── shouldDowngrade (boolean)
        ├── expressionRelationAIRA (string)
        ├── expressionRelation (string)
        └── conditions
            ├── purchase (string)
            ├── numVisits (string)
            ├── points (string)
            └── tracker[]
                ├── trackerName (string)
                ├── value (string)
                ├── trackerId (integer)
                └── trackerCondition (integer)
FieldTypeRequiredDescription
programIdintegerRequiredLoyalty program ID the tier belongs to. Must not be -1.
namestringRequiredTier name. Max 50 characters. Must be unique among live tiers in the program (case-insensitive).
descriptionstringOptionalTier description. Max 500 characters.
colorstringOptionalDisplay color in hex format #RRGGBB (for example, #E5E4E2).
eligibilityobjectOptionalObject containing the conditions a customer must meet to enter this tier.
.kpiTypeenumOptionalKPI the threshold is measured against. Must be one of: CURRENT_POINTS, CUMULATIVE_POINTS, CUMULATIVE_PURCHASES, TRACKER_VALUE_BASED. Case-sensitive. Must be compatible with the program's KPI type.
.thresholdnumberOptionalKPI value at which a customer upgrades into this tier. Between 0 and 2,147,483,647. Must be greater than the previous tier's threshold.
.upgradeTypeenumOptionalWhen tier upgrades are evaluated. Must be one of: EAGER, DYNAMIC, LAZY. Case-sensitive. Must match the program's slab upgrade mode.
.expressionRelationenumOptionalHow multiple eligibility conditions combine. Must be one of: AND, OR. Case-sensitive.
.conditionsarrayOptionalAdditional eligibility conditions.
..typeenumOptionalCondition type. Must be one of: PURCHASE, VISITS, POINTS, TRACKER. Case-sensitive.
..valuestringOptionalCondition threshold value.
..trackerNamestringOptionalTracker display name. Applicable only when type is TRACKER.
..trackerIdintegerConditionalEngine tracker instance ID. Required when type is TRACKER.
..trackerConditionintegerConditionalEngine tracker-definition ID. Required when type is TRACKER.
validityobjectOptionalObject containing the validity period and renewal configuration for the tier.
.periodTypeenumOptionalHow the tier validity period is anchored. Must be one of: FIXED, SLAB_UPGRADE, SLAB_UPGRADE_CYCLIC, FIXED_CUSTOMER_REGISTRATION. Case-sensitive.
.periodValueintegerConditionalTier duration in months. Required and must be greater than 0 when periodType is FIXED. Defaults to 12 when isFixedTypeWithoutYear is true and the value is omitted. Ignored for FIXED_CUSTOMER_REGISTRATION.
.unitstringOptionalUnit of periodValue. Must be NUM_MONTHS.
.startDatestringConditionalValidity anchor date in ISO 8601 format. Applicable for FIXED period types. Must not be sent when periodType is SLAB_UPGRADE or SLAB_UPGRADE_CYCLIC. Must fall on the first day of the month when renewal.shouldDowngrade is true and daily downgrade is off at the program level.
.isFixedTypeWithoutYearbooleanOptionalWhen true, the engine treats startDate as a recurring day-month anchor and ignores the year.
.renewalWindowTypeenumOptionalHow the renewal evaluation window is interpreted. Must be one of: FIXED_DATE_BASED, LAST_CALENDAR_YEAR, CUSTOM_PERIOD. Case-sensitive. Allowed only when periodType is FIXED.
.computationWindowStartValueintegerConditionalMonths-back offset for the start of the renewal evaluation window. Must be 0 or greater. Requires renewalWindowType. Between 1 and 36 when renewalWindowType is FIXED_DATE_BASED. Must not be sent when renewalWindowType is LAST_CALENDAR_YEAR.
.computationWindowEndValueintegerConditionalMonths-back offset for the end of the renewal evaluation window. Must be 0 or greater. Requires renewalWindowType. For CUSTOM_PERIOD, the difference between start and end values must be 35 or less. Must not be sent when renewalWindowType is LAST_CALENDAR_YEAR.
.minimumDurationintegerOptionalMinimum tier duration in months. Must be 0 or greater. The engine doesn't downgrade a customer before this duration elapses.
.renewalobjectOptionalObject containing the renewal trigger configuration for the tier.
..criteriaTypestringOptionalRenewal criteria type. Must be exactly Same as eligibility.
..downgradeToenumOptionalTier the customer moves to on downgrade. Must be one of: SINGLE, THRESHOLD, LOWEST. Case-sensitive.
..shouldDowngradebooleanOptionalWhen false, customers in this tier never auto-downgrade.
..expressionRelationAIRAstringOptionalLogical expression that combines the renewal conditions, in disjunctive normal form (DNF): groups of conditions joined with AND, with the groups joined by OR, for example (1 AND 2) OR 3, where each number refers to a condition. You can also pass the shortcuts ANYn or ALL. When both expression fields are set, expressionRelation applies.
..expressionRelationstringOptionalLogical expression that combines the renewal conditions, in the format used by tiers configured outside this API. Applied as sent.
..conditionsobjectOptionalObject containing the renewal trigger conditions.
...purchasestringOptionalCumulative purchase threshold, passed as a string (for example, "5000").
...numVisitsstringOptionalCumulative visits threshold, passed as a string.
...pointsstringOptionalCumulative points threshold, passed as a string.
...trackerarrayOptionalTracker conditions. Max one entry.
....trackerNamestringOptionalTracker display name.
....valuestringConditionalThreshold value, passed as a string. Required for a tracker entry.
....trackerIdintegerConditionalEngine tracker instance ID. Required for a tracker entry.
....trackerConditionintegerConditionalEngine tracker-definition ID. Required for a tracker entry.

Note: The request body is validated in strict mode. Any unknown field is rejected with HTTP 400. The following read-only or program-level fields must not be sent on create or update requests: downgrade, eligibilityCriteriaType, isActive, reminders, downgradeConfirmation, renewalConfirmation, retainPoints, dailyDowngradeEnabled, isDowngradeOnReturnEnabled, isDowngradeOnPartnerProgramExpiryEnabled, schedule, nudges, notificationConfig, and validity.endDate. Sentinel values of -1 (numeric or string) in programId, periodValue, or threshold are also rejected.

Example response

{
  "data": {
    "tierUniqueId": "ut-973-010",
    "objectId": "6a2aab5cb1f2f8016a6598bb",
    "name": "Super Platinum",
    "description": "Premium tier for top spenders",
    "color": "#E5E4E2",
    "serialNumber": 10,
    "eligibility": {
      "kpiType": "CURRENT_POINTS",
      "threshold": 100000,
      "upgradeType": "LAZY"
    },
    "meta": {
      "createdBy": "75237721",
      "createdAt": "2026-06-11T12:34:36Z",
      "updatedBy": "75237721",
      "updatedAt": "2026-06-11T12:34:36Z"
    },
    "status": "DRAFT",
    "origin": "MONGO_ONLY",
    "renewal": {
      "periodType": "SLAB_UPGRADE",
      "periodValue": "12",
      "unit": "NUM_MONTHS",
      "criteriaType": "Same as eligibility"
    }
  },
  "errors": null,
  "warnings": null
}

Response parameters

FieldTypeDescription
dataobjectObject containing the created tier.
.tierUniqueIdstringUnique ID assigned to the tier (format ut-<programId>-<sequence>). Use it with Get Tier.
.objectIdstringUnique ID of this tier record. Use it with Update Tier, Delete Tier, and the approval endpoints.
.namestringTier name.
.descriptionstringTier description.
.colorstringDisplay color in hex format.
.serialNumberintegerTier position in the program's tier ladder.
.eligibilityobjectObject containing the conditions a customer must meet to enter this tier, as submitted.
..kpiTypeenumKPI the threshold is measured against. Possible values: CURRENT_POINTS, CUMULATIVE_POINTS, CUMULATIVE_PURCHASES, TRACKER_VALUE_BASED.
..thresholdnumberKPI value at which a customer upgrades into this tier.
..upgradeTypeenumWhen tier upgrades are evaluated. Possible values: EAGER, DYNAMIC, LAZY.
.metaobjectObject containing details of who created and last updated the tier, and when.
..createdBystringUser or till ID of the person who created the tier.
..createdAttimestampDate and time when the tier was created, in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ), returned in the server time zone.
..updatedBystringUser or till ID of the person who last updated the tier.
..updatedAttimestampDate and time when the tier was last updated, in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ), returned in the server time zone.
.statusstringCurrent stage of the tier lifecycle. Always DRAFT on creation. Possible values: DRAFT, PENDING_APPROVAL, REJECTED, ACTIVE, DELETED, SNAPSHOT, PUBLISH_FAILED, LIVE.
.originstringIndicates which version of the tier data this entry represents. Always MONGO_ONLY for a new draft. Possible values: BOTH (published tier that also has a draft), MONGO_ONLY (draft not yet published), LEGACY_SQL_ONLY (tier created outside this API).
.renewalobjectObject containing the tier's validity period and renewal settings, derived from validity. Read-only.
..periodTypeenumDefines when the tier validity period starts. Possible values: FIXED (starts on a fixed date), SLAB_UPGRADE (starts when the customer enters the tier), SLAB_UPGRADE_CYCLIC (restarts each cycle after the upgrade), FIXED_CUSTOMER_REGISTRATION (starts on the customer's registration date).
..periodValuestringTier duration in months, returned as a string.
..unitstringUnit of periodValue. Always NUM_MONTHS.
..criteriaTypestringRenewal criteria type. Always Same as eligibility.
errorsarrayError list. null on success.
warningsarrayWarning list. null on success.

Error & warning codes

CodeError numberTypeDescription
TIER.PROGRAM_ID_REQUIRED9003ErrorprogramId is missing. HTTP 400.
TIER.NAME_REQUIRED9001Errorname is missing or blank. HTTP 400.
TIER.NAME_TOO_LONG9002Errorname exceeds 50 characters. HTTP 400.
TIER.INVALID_KPI_TYPE9004Erroreligibility.kpiType or a condition type is not a supported value. HTTP 400.
TIER.THRESHOLD_MUST_BE_POSITIVE9005Erroreligibility.threshold is negative. HTTP 400.
TIER.INVALID_COLOR_CODE9006Errorcolor is not in #RRGGBB hex format. HTTP 400.
TIER.DESCRIPTION_TOO_LONG9008Errordescription exceeds 500 characters. HTTP 400.
TIER.INVALID_UPGRADE_TYPE9009Erroreligibility.upgradeType is not a supported value. HTTP 400.
TIER.INVALID_RENEWAL_CRITERIA9010Errorvalidity.periodType is not a supported value. HTTP 400.
TIER.CLASS_A_PROGRAM_LEVEL_FIELD9011ErrorA program-level field was sent on a per-tier write. HTTP 400.
TIER.CLASS_B_SCHEDULE_FIELD9012ErrorA schedule-shaped field was sent on a per-tier write. HTTP 400.
TIER.ELIGIBILITY_CRITERIA_TYPE9013ErroreligibilityCriteriaType is read-only and was sent on a write request. HTTP 400.
TIER.START_DATE_ON_SLAB_UPGRADE9014Errorvalidity.startDate was sent with a SLAB_UPGRADE family periodType. HTTP 400.
TIER.SENTINEL_STRING_MINUS_ONE9015ErrorA numeric field contains the string sentinel "-1". HTTP 400.
TIER.SENTINEL_NUMERIC_MINUS_ONE9016ErrorA numeric field contains the sentinel value -1. HTTP 400.
TIER.RENEWAL_CRITERIA_TYPE_DRIFT9017Errorrenewal.criteriaType is not exactly Same as eligibility. HTTP 400.
TIER.FIXED_FAMILY_MISSING_PERIOD_VALUE9018Errorvalidity.periodValue is missing or not positive for a FIXED period type. HTTP 400.
TIER.RENEWAL_DOWNGRADE_TO_INVALID9019Errorrenewal.downgradeTo is not one of SINGLE, THRESHOLD, LOWEST. HTTP 400.
TIER.RENEWAL_MULTI_TRACKER9020Errorrenewal.conditions.tracker has more than one entry. HTTP 400.
TIER.RENEWAL_EXPRESSION_INVALID9021ErrorThe renewal or eligibility expression is not a valid DNF expression. HTTP 400.
TIER.VALIDITY_RENEWAL_WINDOW_TYPE9022Errorvalidity.renewalWindowType is not a supported value. HTTP 400.
TIER.VALIDITY_COMPUTATION_WINDOW_ORPHAN9023ErrorA computation window offset was sent without renewalWindowType. HTTP 400.
TIER.VALIDITY_NUMERIC_NEGATIVE9024ErrorA validity numeric field is negative. HTTP 400.
TIER.UPGRADE_VALUE_OUT_OF_RANGE9028Erroreligibility.threshold exceeds 2,147,483,647. HTTP 400.
TIER.TRACKER_ID_REQUIRED9029ErrorA TRACKER condition is missing trackerId or trackerCondition. HTTP 400.
TIER.PERIOD_VALUE_OVERFLOW9030ErrorA numeric value exceeds 25 digits. HTTP 400.
TIER.CUSTOM_PERIOD_DELTA_TOO_LARGE9033ErrorFor CUSTOM_PERIOD, the start-minus-end offset difference exceeds 35. HTTP 400.
TIER.FIXED_DATE_OFFSET_OUT_OF_RANGE9034ErrorFor FIXED_DATE_BASED, computationWindowStartValue is outside 1–36. HTTP 400.
TIER.MIN_DURATION_MUST_BE_POSITIVE9035Errorvalidity.minimumDuration is negative. HTTP 400.
TIER.PROGRAM_KPI_TYPE_MISMATCH9043ErrorThe eligibility condition type is not compatible with the program's KPI type. HTTP 400.
TIER.THRESHOLD_NOT_MONOTONIC9044ErrorThe tier threshold is not greater than the previous tier's threshold. HTTP 400.
TIER.INVALID_PERIOD_UNIT9047Errorvalidity.unit is not NUM_MONTHS. HTTP 400.
TIER.END_DATE_FORBIDDEN_ON_WRITE9048Errorvalidity.endDate is read-only and was sent on a write request. HTTP 400.
TIER.RENEWAL_WINDOW_REQUIRES_FIXED_PERIOD_TYPE9049ErrorrenewalWindowType was sent with a periodType other than FIXED. HTTP 400.
TIER.LAST_CALENDAR_YEAR_FORBIDS_OFFSETS9050ErrorComputation window offsets were sent with renewalWindowType of LAST_CALENDAR_YEAR. HTTP 400.
TIER.PROGRAM_UPGRADE_MODE_MISMATCH9051Erroreligibility.upgradeType doesn't match the program's slab upgrade mode. HTTP 400.
TIER.PROGRAM_DOWNGRADE_STRATEGY_NOT_CONFIGURED9052ErrorThe program has no SLAB_DOWNGRADE strategy. Configure Tier Advanced Settings first. HTTP 400.
TIER.PROGRAM_UPGRADE_STRATEGY_NOT_CONFIGURED9053ErrorThe program has no SLAB_UPGRADE strategy. Configure Tier Advanced Settings first. HTTP 400.
TIER.PROGRAM_TIER_CAP_EXCEEDED9054ErrorThe program already has 50 tiers. HTTP 400.
TIER.DOWNGRADE_START_DATE_MUST_BE_FIRST9055Errorvalidity.startDate is not the first day of the month while downgrade is enabled. HTTP 400.
TIER_NAME_TAKENErrorA live tier with the same name already exists in the program. HTTP 409.
TIER_DRAFT_EXISTSErrorThe program already has an in-progress DRAFT tier. HTTP 409.
TIER_PENDING_APPROVAL_EXISTSErrorThe program already has a tier pending approval. HTTP 409.

Note: Conflict errors (HTTP 409) return the generic error number 999999 with a descriptive message on the wire. The Code column shows the stable symbolic code for these cases.


Body Params
integer
required
string
required
string
string
eligibility
object
validity
object
Headers
string
string
string
Responses

400

Validation error: see the error table in the doc page

409

Conflict: name taken, or a DRAFT or pending tier already exists in the program

Language
Credentials
Basic
base64
:
URL
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json