Free Items and Streaks
How Stash tracks claims of free items in a Real-time Catalog response, and how streaks tracked by Stash work.
A FreeItem is claimable at no cost. When a player claims one, Stash records the redemption and emits a FREE_ITEM_REDEEMED webhook. Two fields govern how claims are tracked:
status: your response is authoritative for whether the gift is offered (AVAILABLE,CLAIMED, orLOCKED), except for items in a streak that Stash tracks for your shop (see Streaks tracked by Stash). After a recorded claim, Stash overridesAVAILABLEtoCLAIMEDon catalog reads so a reload cannot show a consumed gift as claimable. Outside a Stash-tracked streak it only ever applies that one flip: aCLAIMEDorLOCKEDstatus you send is never changed, and Stash never producesAVAILABLE. The override ends at the item'srefreshAt; from then on your status alone decides the next period. For items in a Stash-tracked streak, Stash setsAVAILABLE,CLAIMEDandLOCKEDitself from the player's streak, and ignores the status you send, including when you omit it.claimId(optional): a stable claim identity, separate fromitemId. Free items that share aclaimIdare the same claim for a claim period: claiming any one of them consumes the claim for all of them. When absent,itemIdis the claim identity, which is the existing behavior; integrations that do not send it change nothing.
Use claimId when the item you serve varies per player, for example a daily gift whose itemId differs by loyalty tier. Keep the claimId stable across the variants and the claim still de-duplicates as one gift per period, whichever variant a player sees.
Rules to follow:
- Return at most one item per
claimIdper response; additional items sharing one may be discarded. A locked preview of a later reward must carry a distinctclaimId, or none at all. - A repeat claim inside the same window returns an idempotent success: no duplicate
FREE_ITEM_REDEEMEDwebhook, and no second Loyalty XP credit for gifts that grant XP. - On the
FREE_ITEM_REDEEMEDpayload,itemIdis the item that was granted;claimIdis the claim it consumed and appears only when it differs fromitemId.
Streaks tracked by Stash
A streak is a run of free items that a player claims one per period, such as a daily gift calendar. For a shop where Stash turns on a streak, Stash tracks each player's progress and decides which item is claimable. A shop has 1 such streak. You supply the rewards.
Send the streak in GetCatalog:
- One section, every step. Put all the streak's items in one catalog section as
freeitems: one item per step (or one per tier, below), for every sequence, with the rewards for this player. Give each item its ownitemId, and do not share aclaimIdbetween items: Stash keys the streak's claims itself, so the per-variantclaimIdpattern above does not apply. - Number the steps with
streakOrder. Start at 1 and continue across sequences: with 7-step sequences, step 1 of the second sequence is 8. Set it on every free item in the section or on none; when no item sets it, Stash numbers the free items that apply to the player (those withouttargetTierIdand those for the player's current tier) in the order they appear in the section agreed for your shop or, if none is agreed, in the first section of your catalog that contains only free items. SetstreakOrderwhenever any item in the section setstargetTierId. - Keep the layout whole. The numbers run from 1 with no gaps, and they cover a whole number of sequences. The sequence length is set for your shop (7 unless agreed otherwise). Set
streakOrderin 1 section only. If the section's items break these rules, Stash hides the streak's free items, and if more than 1 section setsstreakOrder, it hides the free items of each of them. When no item setsstreakOrderand no section is agreed for your shop, Stash only infers the section, so a section that breaks these rules is shown as you sent it, with your ownstatusvalues, and Stash tracks no streak in it. If the section agreed for your shop is missing from a response, Stash shows no streak for that response. - Vary rewards by loyalty tier if you need to. For a step whose reward depends on the player's tier, send one item per tier with the same
streakOrderand that tier'stargetTierId, and optionally one item withouttargetTierIdfor players with no matching tier. Each number has at most one item per tier and one withouttargetTierId. Stash shows the player only the item for their current tier, or else the one withouttargetTierId, and the claim'sFREE_ITEM_REDEEMEDwebhook carries theitemIdof the item the player claimed. If you serve only the player's own tier (Stash sends it in thecurrentTierIdquery parameter ofGetCatalog), send that tier's items.
What Stash does with it:
- Sets each item's status. Stash shows the player's current sequence only. Earlier steps are
CLAIMED, the step that is due isAVAILABLE(CLAIMEDonce taken), and later steps areLOCKED. Stash also setsmaxClaimable: 1 on the step that can be claimed, 0 on every other step. You do not need to sendstatusormaxClaimableon these items; if you do, Stash ignores them, whatever the values. - Locks the streak when it cannot decide. If Stash cannot read a player's progress, or, for a streak with tier rewards, their loyalty tier, every step shows as
LOCKEDand nothing is claimable until it can. With the skip option, the same applies when no step has an item for the player. Players who are not signed in do not see the streak's items. - Uses your
refreshAtas the period end. SendrefreshAton each item, set to the next reset. Stash uses it as the end of the current period and shows a countdown to it. When it is missing, already past, or more than one period ahead, Stash uses the reset agreed for your shop instead. - Resets per shop. A period is a day or a week, starting at a time of day in a time zone agreed for your shop (00:00 UTC unless agreed otherwise). In a time zone with daylight saving, the reset follows local time. Weekly periods start on Monday. Send the same time in
refreshAt, and use it for any once-per-period check on your side. - Advances only on a claim. A player can claim one step per period, and only the step that is due. Claiming the last step of a sequence moves the player to the next sequence, and claiming the last step of the last sequence wraps the streak to step 1. A missed period sends the player back to step 1 of the sequence they are in, the one holding the step that was due: a player who misses a day in the middle of a sequence starts that sequence again, a player who claimed the last step of a sequence and then misses a day starts the next sequence at its step 1, and after the last step of the last sequence they start again at step 1. A period in which the streak is turned off or its items are missing counts as missed.
- Handles steps without a reward for the player. When the due step has no item for the player's tier and none without
targetTierId, there is nothing to claim. By default the period counts as missed, and as after any miss the player goes back to step 1 of the sequence that step is in. So a player whose tier has no item for a step claims the steps before it, cannot claim that step, and starts the sequence again, every time, never getting past it. To avoid this, send an item for every step to every tier you target, or an item withouttargetTierIdfor that step. If step 1 of the sequence also has no item for the player, they stay on it until you send one. If agreed for your shop, the next step that has an item for the player becomes due in the same period instead. - Keeps the streak across loyalty seasons. By default a new loyalty season does not change a player's place in the streak. If agreed for your shop, and your loyalty seasons run in Stash, a new season restarts the streak: the player's first claim in a season other than the one of their last claim is step 1, and a claim already made in the current period stays claimed. A time with no live season does not count as a new season. Items for tiers that are not in the live season are not shown.
- Keeps the player's place when rewards change. If the rewards you send for a player change, for example with their segment, the player stays on the same step and sees the new reward for it. If you send fewer steps than a player has reached, their place wraps back to the matching step from the start.
- Queues the grant before it records the claim. Grant the reward when you receive the claim's
FREE_ITEM_REDEEMEDwebhook. Stash records a claim only once its webhook is queued, so a streak needs an enabled webhook endpoint for your shop: without one, every claim fails and nothing is recorded. If a claim fails after its webhook was queued, the player's retry in the same period is the same redemption: its webhook carries the sameredemptionIdas long as the period'srefreshAthas not changed, so de-duplicate on it.
How is this guide?