FAQ / Loyalty

Loyalty: Questions and Answers

Loyalty programs, how steps complete, reporting game events, reward cards and the console. 33 questions, grouped by the documentation page each one is about. Where a response or webhook carries a figure, read it there rather than recomputing it.

Loyalty & Rewards

Read the Loyalty & Rewards page

What is a loyalty program, and how is it made of steps?

A loyalty program is a short quest inside your game: a list of steps a player completes (for example buy currency, complete five matches, transfer value to another game) that unlocks a real reward such as a gift card or discount code. Each step is an action from a library, with details you set such as a minimum amount, a count, a level, or a destination game. Every program also has a reward, a window and a card that renders it for the player.

Must steps be completed in order?

Only if you build the program that way. Each program has an order_mode of ordered (a step after the first unfinished one shows as locked) or any_order (every unfinished step is open and can be worked on at once).

Which currency actions does INVO observe directly, and which gameplay actions must my game report?

INVO records currency purchases, transfers to and from another game, currency sends and receipts, coin spends on items, and subscription activations and renewals on its own, including their refunds and reversals, so those steps need nothing from you. Gameplay actions (sessions played, coming back after a break, reaching a level or milestone, playing several of your titles, and custom events such as match_completed) move only when your game reports them through POST /api/sdk/loyalty/server-events (trusted) or POST /api/sdk/loyalty/events.

Why does every program need a qualifying currency step, and why doesn't receiving currency count?

Every program you build must include at least one currency purchase, transfer to another game, or currency send, because that is what ties engagement in the program to revenue in your game. Receiving currency is something that happens to a player rather than an action they take with money, so it does not qualify. The builder flags a program without a qualifying step while you edit, and it cannot be submitted.

What reward types can players earn, and who funds campaign rewards?

Players earn gift cards, discount codes and similar rewards from brands INVO works with. In an INVO campaign, INVO funds the reward: you never pay for or top up the rewards your players earn.

Can I see what a reward costs?

No. The console shows a reward's name and how many remain (for example "Limited: 120 remaining"), never its cost, and the participants and report views never carry a cost either.

What does the program window define?

The window sets when the program runs (starts_at to ends_at) and how long a player has to finish once they start (completion_hours). On a player's card, window_ends_at is when that player's time to finish runs out, and completion_note gives a ready-to-show sentence when the program has no fixed limit.

What does a program card show?

A card shows the program title, description, brand and art, the reward, each step with its summary, state (complete, open or locked) and progress such as 3 / 5, the overall steps_complete of steps_required, the time window, and any rewards the player has unlocked (codes masked). The card you preview in the console is built by the same code as the card your players see.

What is the difference between joining an INVO campaign and building my own program?

Joining a campaign means enrolling your games so the programs INVO offers in that campaign appear on those games' cards. Building your own program means composing one inside a campaign's limits: you pick the steps, the reward from the campaign's list, the window and the card text, preview it, and submit it for INVO's review.

How do players see progress: in my UI, the hosted My rewards page, or both?

Either or both. You can draw your own UI from GET /api/sdk/loyalty/me/card (player token) or from your server with GET /api/sdk/loyalty/players/rewards, and you can open the INVO-hosted My rewards page with a link from POST /api/sdk/loyalty/me/rewards-page.

When is a reward code revealed, and where is it masked?

The full code appears only in the response to POST /api/sdk/loyalty/me/vault/{vault_entry_id}/redeem (or the Redeem button on the hosted page). Everywhere else, including the card, the vault list, the server read, and the console report and Participants views, a reward shows only code_masked, for example ••••ABCD.

How do I earn revenue from programs?

Programs earn through the money steps they require: the currency purchases, transfers and sends your players make to complete a program are ordinary transactions, and your share of them is paid to you as usual under your normal fees. There is no separate payment for running a program, and in INVO campaigns the reward itself costs you nothing.

Integrating Loyalty

Read the Integrating Loyalty page

Which header does GET /api/sdk/loyalty/me/card require, and what happens with the game secret instead?

It requires the player's SDK token as Authorization: Bearer <player token> (X-Invo-SDK-Token is also accepted). Sending only X-Game-Secret-Key is refused with 401 SDK_TOKEN_MISSING, because a game secret never identifies a player and must never ship in a client; read a player's cards from your server with GET /api/sdk/loyalty/players/rewards instead.

When should I use /players/rewards instead of /me/card?

Use GET /api/sdk/loyalty/players/rewards?player_email=... with X-Game-Secret-Key when your game server needs a player's progress without a player token, for example to render server-side UI or send its own "2 matches to go" notifications; it returns exactly the /me/card body for that player in your game. You can also POST it with a JSON body {"player_email": ...} to keep the email out of the URL. Use /me/card from the game client with the player token.

What does a card status of in_review mean?

in_review means the player has finished every required step and the reward is being checked before it is released. Show the program as complete and the reward as pending; it appears in rewards[] once released.

How do I decide whether a step is open, locked or complete in ordered versus any_order programs?

You do not decide it: read steps[].state as returned. In an ordered program, steps before the first unfinished step are complete, that step is open, and later unfinished steps are locked; in any_order, every unfinished step is open.

When is steps[].progress null, and is state or progress authoritative?

progress is null in the console preview, and on a live card when the count could not be read this time; render the step's state alone then. state is authoritative: progress is for display only, and current reaches target only when state is complete.

What is the difference between can_redeem and can_reveal_again, and what does reveal_until control?

can_redeem is true for an unlocked reward the player has not yet redeemed. can_reveal_again is true for an already redeemed reward whose code can be shown once more by calling redeem again (the response then has revealed_again: true), and reveal_until is the time after which the code can no longer be shown again.

What should I do when redeem returns already_redeemed, vault_entry_not_found or vault_entry_expired?

already_redeemed means the reward was redeemed and its code can no longer be shown, so tell the player it was already used. vault_entry_not_found means there is no such reward for this player (refresh the vault or card; a reward can only be redeemed by the player who holds it), and vault_entry_expired means it expired before it was redeemed. None of these is fixed by retrying; the SDKs expose them as isRewardAlreadyRedeemed, isRewardNotFound and isRewardExpired.

Why does the redeem response use Cache-Control: no-store?

The redeem response is the only place a reward code appears in full, so it is sent with Cache-Control: no-store to keep browsers, proxies and caches from keeping a copy. Show the code to the player straight away and do not log, cache or store the response.

Which event types can I send to server-events, and which are refused with EVENT_TYPE_NOT_ALLOWED or RESERVED_EVENT_TYPE?

Games report game.* types: game.session.started, game.session.heartbeat, game.session.ended, game.milestone.reached and game.custom.recorded (with an event_name you registered in the console). POST /api/sdk/loyalty/server-events refuses any type that does not start with game. with 400 EVENT_TYPE_NOT_ALLOWED, and the client route POST /api/sdk/loyalty/events refuses the invo.* and partner.* types INVO reports itself with 400 RESERVED_EVENT_TYPE.

Why must I resend the same event_id on retry?

event_id is how an event is deduplicated: resending the same UUID on a retry guarantees the event counts once, while a new id makes the retry a second event that can double-count progress. If you omit event_id, INVO assigns a fresh one per request, which is why you should generate it yourself, keep it, and resend it.

Does a client-reported event complete a step or pay a reward?

A client-reported event can move a gameplay step forward and even complete it for display, but a real-value reward is paid only when its gameplay steps were completed on server-reported events. Report gameplay events from your game server with POST /api/sdk/loyalty/server-events before going live; there is no endpoint that marks a step complete directly.

Why can't the hosted My rewards page be embedded in an iframe, and how long is its link valid?

The page reveals reward codes, so it refuses to be framed (frame-ancestors 'none' and X-Frame-Options: DENY) to protect against another site overlaying or capturing it; open the url in the system browser or a web view. The link from POST /api/sdk/loyalty/me/rewards-page is personal to the player and valid for 15 minutes (expires_at), so mint a fresh one each time the player opens the page and never store or share it.

Loyalty Programs in the Developer Console

Read the Loyalty Programs in the Developer Console page

Which campaign details should I check before building a program?

Check the rewards on offer and how many remain, which actions are allowed as steps and how many steps a program may have, the dates, regions and audience (including any minimum player age), which kinds of title it admits (games, platforms or both), and how programs are reviewed. A title can only enroll in a campaign that admits its type.

How do I enroll a game in a campaign, and when do players see it?

In the console, open the campaign, enroll the games that should carry it, and confirm your game's audience age if the campaign asks for it. Once a game is enrolled, the campaign's live programs appear on that game's cards for its players.

How do I register a custom event name such as match_completed?

In the console, register the name for your game (for example match_completed), optionally with the range of values it may carry, before you use it as a step or report it. Your server then reports it as game.custom.recorded with payload.event_name; an unregistered name or an out-of-range value is refused with 422 validation_failed.

Does the step order setting change how progress is tracked?

Events and money actions are recorded either way; the setting changes which steps a player can work on and how they display. In an ordered program, steps after the first unfinished one show as locked, while in any order every unfinished step is open.

Can I save an incomplete draft, and which checks block submission?

Yes, a draft saves whatever its state. The builder checks it against the campaign's current rules as you work and points at the exact step or field to fix; those problems (for example a missing qualifying currency step, a step type the campaign does not allow, too many steps, or an action not yet available to your studio) block only submission.

What actions are available in each program state (draft, submitted, approved, live, paused, ended, rejected)?

draft: edit, preview, delete, submit. submitted: withdraw back to draft. approved: launch (or choose at submission to go live as soon as it is approved). live: pause or end. paused: resume (unless INVO paused it) or end. ended: read the report. rejected: read the reason, edit it (it returns to draft) and submit again.

How do I find where players stall in the program report?

The report lists, per step, how many players completed it and how many unfinished players are stalled on it as their next step; start with the step that has the most stalled players. The report also shows players started and completed, and rewards issued, redeemed and remaining.

How do Participants filters and reward states work?

Participants lists your players who started a program that has gone live, by the email they have in your game, with their status, steps completed, start, deadline and completion times, and each earned reward's state (unlocked, reserved, redeemed, expired or revoked, codes never shown). You can filter by status (such as in progress, completed or expired) and page newest or oldest first. A row with no email is a player who could not be matched to your player list; find them by email in the Players tab.

How does the Players tab help support answer "where is my reward?"

In the Players tab, pick the game and search by the player's email to see their progress across your programs and the rewards they have earned. You can see which step is still open or that the reward is unlocked and waiting to be redeemed; your server can read the same data with GET /api/sdk/loyalty/players/rewards.

Back to the FAQ hub. Something not answered here? Email partners@invo.network.