Create an audience of users who have an unredeemed voucher in their wallet
Introduction
Sometimes you need to target users based on the vouchers currently sitting in their wallet rather than an event they've reported. A common example is sending a push notification to everyone who holds a specific voucher but hasn't redeemed it yet — a nudge to use it before it expires.
Because voucher wallet contents aren't exposed as standard query-builder data points, this audience is built using a JSONata expression. This gives you fine-grained control over which vouchers count, including their redemption, void, and expiry status.
Each expression below starts by declaring the values you need to edit. Update the variable(s) at the top of the expression, then paste the whole thing into the criterion — you don't need to touch the logic underneath.
Configuration
Navigate to Users > Audiences and click Create in the top right corner.
Give the audience a name and description. Turn on
AUDIENCE_JOINEDandAUDIENCE_LEFTevents if needed. Set the refresh rate to Daily Reactive (voucher expiry changes over time, so the audience needs to re-evaluate on a schedule).Move to the criteria tab and add a JSONata expression criterion. Use the expression below, editing the variable at the top:
(
$rewardId := "enter reward ID here"; /* ← EDIT: the reward ID of the voucher you're targeting */
$exists(rewardData[0].vouchers[
reward.id = $rewardId
and redeemedAt = null
and voidedAt = null
and (expiresAt = null or $toMillis(expiresAt) > $millis())
])
)Click save.
How the expression works
The expression checks the user's active vouchers for at least one that matches every condition:
reward.id = $rewardId— the voucher is for the specific reward you set at the top.redeemedAt = null— the voucher has not been redeemed.voidedAt = null— the voucher has not been voided.expiresAt = null or $toMillis(expiresAt) > $millis()— the voucher either never expires, or its expiry is still in the future.$millis()returns the current time in milliseconds, and$toMillis()converts the voucher's expiry timestamp for comparison.
$exists(...) returns true if one or more vouchers match, so the user joins the audience. When they redeem the voucher, it's voided, or it expires, they no longer match and leave the audience on the next refresh.
Variants
A specific voucher due to expire within a set time
Target holders of a specific, still-valid voucher whose expiry falls within the next X days — ideal for a "use it before it's gone" reminder. Edit both variables at the top.
A specific voucher held for longer than a set time
Target holders of a specific voucher that's still valid (unredeemed, unexpired, unvoided) but which they've had in their wallet for more than X days — based on when the voucher was issued. Good for re-engaging users who've been sitting on a voucher without using it. Edit both variables at the top.
ANY voucher due to expire within a set time
Same as the specific-expiry variant but ignores the reward ID, so it matches any active voucher the user holds that's expiring within the window. Good for a generic "you have a voucher expiring soon" campaign — edit only the number of days.
ANY unredeemed, valid voucher
Matches users holding at least one active voucher of any kind that hasn't been redeemed, voided, or expired — useful for re-engaging users who have unused rewards waiting. Nothing to edit.
Holds a specific voucher, regardless of expiry
If you don't care about the expiry date and only want everyone currently holding a specific, unredeemed, non-voided voucher — edit only the reward ID.
Tips
Finding the reward ID: The
reward.idvalue is the underlying reward ID of the voucher, not the voucher instance ID. You can find it on the reward in the Loyalty Console.Editing the variables: Only change the lines marked
← EDITat the top of each expression.$daysToExpiryand$daysHeldare plain numbers of days — the expression converts them to milliseconds for you, so there's no maths to do.Set the refresh rate to Daily Reactive for any time-based variant. Expiry and wallet age change over time, so the audience must re-evaluate regularly: for the "expiring soon" variants, users join as their expiry date approaches and leave once the voucher lapses; for the "held longer than" variant, users join once a voucher passes the age threshold.
Combine with a campaign: Once the audience is populated, attach it to a marketing campaign to send the push notification. See the Marketing module for setting up the notification itself.
Test with a known user: Before relying on the audience, confirm a user you know holds the voucher appears in it. If they don't, double-check the reward ID.
Last updated
Was this helpful?