VIP tiers with yearly windows and benefits
Qualify members per calendar or membership year, keep a tier through the following year, add a grace period, declare benefits and gate offers by tier.
A tier program ranks members by what they earned in one currency. This guide covers the yearly programs most VIP schemes use: a member qualifies during a year, keeps the tier for the rest of that year and the whole next one, and sees what each tier gives them.
1. Choose the qualification window
basis says what counts towards a tier.
basis.type | What counts |
|---|---|
lifetime_earned | Everything the member ever earned |
balance | The available balance right now |
earned_rolling_days | Earned in the last days days |
earned_calendar_year | Earned since 1 January, in the environment time zone |
earned_anniversary_year | Earned since the member's latest anniversary of the day they were created |
Earned amounts are net of reversals: a refunded purchase stops counting in the year it was earned. A member created on 29 February has their anniversary on 28 February in other years.
2. Create the program
curl -X POST "$ORISHARE_API/v1/tier_programs" -H "Authorization: Bearer $SECRET_KEY" \
-H "Idempotency-Key: vip-program" -H "Content-Type: application/json" \
-d '{
"name": "VIP",
"currency": "points",
"basis": { "type": "earned_calendar_year" },
"downgrade_check": "daily",
"retention": { "mode": "through_next_period", "grace_days": 14 },
"levels": [
{ "name": "Member", "threshold": 0 },
{ "name": "Silver", "threshold": 500,
"benefits": [{ "key": "birthday_gift", "title": "Birthday gift" }] },
{ "name": "Gold", "threshold": 1000,
"benefits": [
{ "key": "free_shipping", "title": "Free shipping", "description": "On every order", "icon": "truck" },
{ "key": "early_access", "title": "Early access to sales" }
] }
]
}'Members move up as soon as they qualify: a rule with the tier.evaluate action, or
POST /v1/tier_programs/{id}/evaluate for one customer. Moving down only happens in the
scheduled check (downgrade_check: daily, monthly or never).
3. Retention and grace
retention is optional. Without it a program behaves as it always did.
mode: "through_next_period"keeps a tier earned in a year until the end of the following year. Gold earned in 2026 lasts through 2027. If the member reaches Gold again in 2027 it lasts through 2028; if they only reach Silver in 2027 they move to Silver at the start of 2028, and if they earn nothing they move to the first level. It needs a calendar or anniversary basis.grace_days(0 to 366) delays any downgrade. The first check that finds a member below their tier records a date that many days ahead instead of moving them. Qualifying again before that date cancels it. Grace works with every basis.
Use downgrade_check: "daily" with a grace period. A monthly check only looks once a month, so
the downgrade would wait for the first check after the grace date.
Setting a member's tier by hand (POST /v1/customers/{id}/tiers) is not protected by retention:
the next scheduled check moves them to the tier they qualify for, after the grace period if
there is one.
4. Read a member's tier
curl "$ORISHARE_API/v1/customers/user_42/tiers" -H "Authorization: Bearer $SECRET_KEY"{
"data": [
{
"customer_id": "cust_...",
"program_id": "tp_...",
"level": "Silver",
"since": "2026-10-04T15:02:11.000Z",
"last_evaluated_at": "2026-10-04T15:02:11.000Z",
"source": "evaluate",
"qualifies_until": "2028-01-01T05:00:00.000Z",
"grace_until": null,
"benefits": [{ "key": "birthday_gift", "title": "Birthday gift" }],
"next_level": {
"name": "Gold",
"threshold": 1000,
"benefits": [{ "key": "free_shipping", "title": "Free shipping" }]
}
}
],
"next_cursor": null,
"has_more": false
}qualifies_untilis when the tier is next up for review: the end of the year it was earned in, or of the following year withthrough_next_period. It isnullfor programs without a yearly window and while a downgrade is pending.grace_untilis set while a downgrade is pending and says when it takes effect.next_levelisnullat the top tier.
5. Benefits
Benefits are a declared list per level (up to 20), for your storefront and emails to show. Each
has a key (lowercase letters, digits and underscores, unique within the level), a title, and
an optional description and icon. Declaring a benefit grants nothing by itself: deliver it
with a rule, a tier-gated offer, or your own code reading the member's tier.
When you update a program, a level sent without benefits keeps the list it has; send
"benefits": [] to clear it. Config export and import carry retention and benefits.
6. Offers for a tier and above
A catalogue offer can require a minimum tier in its eligibility:
{
"eligibility": {
"audience": [],
"minimum_assurance": "authenticated_customer",
"minimum_tier": { "tier_program": "VIP", "min_level": "Gold" }
}
}tier_program is the program's id or name. Members at min_level or any higher level may
redeem; everyone else sees the offer as not available to them. A member who was never evaluated
counts as the first level.
Changing an existing program
Changing basis re-evaluates every member, so it needs "reevaluate": true on the update.
Changing retention or benefits does not move anyone; retention takes effect at the next
scheduled check.