CEEJAYDocs

Quests, shop and rank in your game

Show the community's quests, shop, locker, rank, daily reward and surveys in your game, and sell from its shop, with rules that keep the player's coins safe.

The game loop lets a game show the community's quests, shop, locker, rank, daily reward and surveys for a player who is connected to their Discord account, and lets the player act on them from inside the game: start a quest, buy an item, claim it, collect the daily reward. The community's team keeps control of what the game may sell and how much a player may spend.

This page is for the studio's developers. It says what a game can show and do, what has to be true first, the rules about the player's coins, and how your own server receives a purchase.

What this page covers

The thirteen requests are in the API reference under The game loop: from the game. The player has to be connected first: Connect explains how. To send the requests from a game, use connect.hub of the Connect client in the TypeScript SDK, a game kit, or the recipe for any other engine. The kits and the recipe do not have functions for the loop yet.

What a game can show and do

RequestWhat it doesCoins
List the questsThe quests, each with its tasks and the player's progress
Start a questOpens a quest for the player
Verify a quest taskVerifies a task whose state CEEJAY can read, and completes it if the check passes
Answer a quest taskSends the answer to a task that asks a question
List the shopThe items this game may sell, with whether the player can buy each one now
Buy a shop itemBuys an item with the player's coinsSpends
Read the lockerWhat the player owns through the game
Claim an itemClaims a purchase that is ready for the playerRedeems the purchase
Get the ranksThe player's level and place, and the top players of the game
Get the balanceThe coins, the streak, the perks, the XP boost, and what this device may spend today
Check inClaims the daily rewardEarns
List surveysThe surveys the community shows in this game that the player can answer now
Answer a surveySends the player's answers, and grants the survey's rewards the first time

A quest completed from the game grants the same rewards as in Discord: XP, coins, a badge, a role. The quest's own limits apply, such as how often it can be repeated and the community's daily quest limit.

The loop leaves some things out. A game cannot refund a purchase, change a price, or mark a delivery as fulfilled: your server does that with Complete a shop delivery. It cannot use a perk, skip a quest task or report an event from the game, and it shows no coin leaderboard. The locker shows what the game sold and what the community's team put on its list. A reward a member earned has no shop item, so it does not appear in the locker.

Surveys in the game

A survey is a form from the community's Surveys & Forms page with In game switched on under Where it shows. The team picks the game, or every game, and can make a survey wait for an event your game already logs with Log player events: for example, after match_end has happened 3 times since the survey opened. List surveys returns only the surveys due for the player now, so call it after the moments you log, and show one when it fits: after a match, or from a menu.

Each question comes with its key and a type that says how to ask it. Draw it with your game's own interface and send the answers back by key with Answer a survey. CEEJAY checks them by the rules Discord uses, saves them to the member's response beside answers given in Discord and the Member Hub, and grants the survey's rewards once, wherever the member answers. Nothing a game sends starts a direct message.

What has to be true first

Each of these has its own refusal. They are checked in this order, after the player session itself:

WhatRefusalWhat to do
This instance has the loop. Community details reports it as features.gameLoop404 with the code not_availableHide the loop
The community's team switched the loop on for your game. Get the player's profile reports it as hub.enabled409 with the code hub_not_enabledHide the loop. The team turns it on
The Discord account is in the server409 with the code membership_required. The body adds membership, and joinUrl for left and not_memberSend the player to joinUrl. A member who has not passed Discord's membership screening gets pending as membership and no joinUrl: they complete the screening in Discord
The member has consented to share their quests, rewards, shop and rank with your game409 with the code sharing_needed. The body adds manageUrlSend the player to manageUrl

A paused game returns 409 with the code game_paused, and a game directed at children returns 403 with the code audience_not_allowed. Buying and claiming need more, because they spend the player's coins: see The rules about money.

What the member consents to

Consent is part of connecting. For a game that has the loop on, the connect page and the confirm step in Discord state what data the game receives, and consent is not offered as a separate checkbox. Nothing is saved until the member gives consent.

The game receives which quests the member started or finished and their progress, their daily reward streak, perks and XP boost, what they buy through the game and what is in their locker, and their rank in the community. Their name, level and XP also show in the top ten of the game, where its other players can see them.

The consent text states the spending: "This game can spend your coins on its shop items, up to N a day", with the game's daily limit in place of N. For a game whose limit is 0 it reads "This game cannot spend your coins".

A member who consented is asked again when the community's team switches the loop on, raises the daily limit, adds an item type, or adds an item to the game's list. Until they consent, sharing.needed of Get the player's profile lists hub and every request of the loop returns sharing_needed. The member consents again at manageUrl, with nothing but their Discord account.

The rules about money

Reading, quests and the daily reward take nothing from the member. Only Buy a shop item spends coins, and Claim an item redeems a purchase. Both follow these rules, and a game cannot change any of them.

An item is on the game's list. A game sells only the items the community's team put on its list, and only of the item types the game is set to sell, which by default is items delivered by an API. The list is empty until the team adds items, so a game sells nothing at first. An item that is not on the list cannot be bought through the game: Buy a shop item returns the same error as for an item that does not exist. Without this list, one game could buy the items of another.

The price is validated. A game sends the price the player saw as expectedPrice. When the item's price now differs, nothing is bought. A game never decides a price, a balance or a reward.

Spending requires a verified device, when the game asks for it. The community's team sets, for each game, whether a connection where the game supplied the player ID without verification may spend. By default it may not.

The deviceReading, quests, check inBuying and claiming
Verified: the game verified who the player isYesYes, once the hold period has ended
Basic, and the game requires verification (the default)YesNo. 403 with the code verified_proof_required
Basic, and the team allows a basic connection to spendYesYes, once the hold period has ended

Anyone with the game's public key can supply any player ID, so a basic connection does not verify who the player is. Connect explains the two levels.

New devices have a hold period before they can spend. A new connection, a move to another player, and each new device have a hold period before they can spend. The hold period is 24 hours unless the team set another number of hours for the game, and 0 removes it. A device must also be at least as old as the hold period, whether it was approved in Discord or verified at connection. A player on a new phone, or one who reinstalled the game, cannot buy until the hold period ends. The hold that applies is the latest of the connection's hold, the device's hold, and the device's age plus the game's hold hours. It is spending.holdUntil in Get the balance, and a request refused for it is 409 with the code spend_on_hold, holdUntil and retryAfter.

The hold period exists because a stolen refresh token remains valid for 90 days. It gives the member time to see the new device on their connections page and sign it out.

There is a daily limit. The game can spend a set number of coins a day for each member. The day is the UTC day. The limit is 5,000 coins unless the team set another number for the game, and 0 switches spending off. It counts the coins charged through this game since midnight UTC, excluding refunded purchases (a purchase the team rejected without refunding the coins still counts), and it is tracked for each member and each game: a member in two games has two limits. Purchases in Discord do not count. Past it, a purchase is 409 with the code daily_spend_cap_reached, with cap, spentToday, price, resetsAt and retryAfter. An item that costs more than the limit can never be bought through the game. The quests and the daily reward are not counted: they earn coins.

Purchases are idempotent. Every purchase carries an idempotencyKey the game chose, and a repeat with the same key never buys twice. Buying and claiming together are also limited to 60 an hour for one member in one game.

No direct messages. CEEJAY never sends a member a direct message (DM) for anything a game starts: not a purchase, a refund, a quest, a level or a reward. A task that the community's team reviews is completed in Discord, because the team's decision is sent there, and a game never submits an answer for review.

What a game never receives

  • A Discord ID, an avatar or anything about another member. The top list of Get the ranks contains a display name, a level and XP for players of this game who consented to share it.
  • A code a member owns. Read the locker returns hasCode: true, and the member reads the code in Discord.
  • What the member typed when buying, a delivery address, a secret, or the text of a delivery error.
  • A link to connect an account on a platform. A task that needs one says which platform, and the member does it in Discord.
  • A balance of someone else, or a coin leaderboard.

Every response is private to the player and includes Cache-Control: no-store.

How your server receives a purchase

An item that is Delivered by your API is bought in the game like any other. CEEJAY then sends the signed delivery to the item's delivery URL, as Deliver shop items from your own platform describes. For a purchase made through a game, the body includes player: the game's slug as game, the game's own ID for the player as player_id, and proof (basic or verified), as they were when the member bought. Your server delivers the item to that player.

player is read from the purchase, never from the connection as it is now, so a player who moves to another ID between the purchase and a retry does not redirect the item. A studio that trusts only verified players checks proof and responds failed for a basic player: the player is refunded. Until your server completes a delivery it responded to with pending, the locker shows waitingFor: "studio".

A purchase made in Discord, a reward a member earned and a test delivery carry no player. List shop purchases returns the same values as player, with playerId, and a player erased with Delete a player has no player on a retry. The signature covers the whole body, so a receiver that ignores the field is unaffected.

The order of a first screen

  1. Renew the player session, or let the Connect client do it, and check that the player is connected.
  2. Read Get the player's profile. When hub.enabled is false show nothing of the loop. When sharing.needed lists hub, send the player to manageUrl.
  3. Read Get the balance for the coins and for spending.maySpend, which indicates whether a Buy button should be enabled.
  4. Read List the quests and List the shop, a page at a time.
  5. Call Read the locker for what the player owns and can claim, and Get the ranks where the screen shows a leaderboard.

Retrying safely

RequestAfter a lost response
The five readsRetry it. It changes nothing
Start a quest, Verify and Answer a quest task, Claim an itemRetry it. A repeat returns that it was already done
Buy a shop itemRetry with the same idempotencyKey. Nothing is bought twice
Check inDo not retry it automatically. A repeat returns checkin_cooldown, which means the reward is already claimed

Limits

A player session can make 120 reads and 20 writes a minute, and 140 requests of any kind. Rate limits has the numbers.

On this page

Community StudiosPrivacyTerms