Gamification API
Manage scannable score objects and read the computed leaderboard.
Manage the collectible “score objects” attendees scan during a treasure hunt, and read the resulting leaderboard. All endpoints require the standard authentication headers. Write endpoints require the gamification:write scope; read endpoints require gamification:read.
What this API cannot do
It cannot award points. Points are earned when an attendee scans an object’s QR code in the app. This API sets up the objects and reads the standings, but it cannot give anyone points directly - so every point on the leaderboard traces back to a real scan.
GET /getScoreObjects
Returns the event’s score objects, sorted by name. Deleted objects are left out. Requires gamification:read.
[
{
"scoreObjectId": "sc1",
"documentId": "sc1",
"name": "Main stage banner",
"points": 10,
"hint": "Look behind the keynote stage.",
"bonusQuestion": "Which hall is this in? [A,B,C]",
"bonusChoices": ["A", "B", "C"],
"bonusAnswer": "B",
"bonusPoints": 5,
"qrPayload": "SCOREOBJECT:sc1"
}
]
qrPayload is the exact string to encode in a QR code for that object, so you can print your own codes without reverse-engineering the format. bonusChoices is null for a free-text bonus question.
POST /upsertScoreObject
Creates an object when scoreObjectId is omitted, edits one when it is supplied. Requires gamification:write.
| Field | Type | Required on create | Notes |
|---|---|---|---|
scoreObjectId |
string | - | Omit to create. |
name |
string | Yes | Max 200 characters. |
points |
number | Yes | Decimals allowed; rounded when scoring. |
hint |
string | No | Shown to attendees hunting for it. |
bonusQuestion |
string | No | Asked after scanning. See the bracket syntax below. |
bonusAnswer |
string | No | Compared case-insensitively and trimmed. |
bonusHint |
string | No | |
bonusPoints |
number | No | Extra points for a correct bonus answer. |
Multiple-choice bonus questions
Wrapping comma-separated choices in square brackets turns the bonus into multiple choice:
{ "bonusQuestion": "Which hall is this in? [A,B,C]", "bonusAnswer": "B", "bonusPoints": 5 }
The text before the bracket is the prompt; the bracketed values are the only options an attendee can pick. Because of that, the API rejects two configurations that would otherwise be unwinnable:
bonusAnsweris not one of the offered choices - no attendee could ever answer correctly.- Brackets containing fewer than two choices.
It also refuses to set bonus points with no correct answer to check against, and warns you if you ask a bonus question that is worth nothing.
These checks look at the finished object, not just this request, so you can set the answer in one call and the points in the next.
POST /deleteScoreObject
Requires gamification:write.
{ "scoreObjectId": "sc1" }
The object is recoverable in the console afterwards. It is not consequence-free, though: points only count while the object exists, so every attendee who already scanned it loses those points from their total. The response says how many people that affects.
{ "status": "success", "warnings": ["18 guest(s) had already scanned this object and lose its points from the leaderboard."] }
GET /getLeaderboard
Returns the ranked standings, computed on the server. Requires gamification:read.
| Query parameter | Required | Description |
|---|---|---|
limit |
No | Return only the top N (max 1000). |
includeHidden |
No | 1 to include guests whose profile is not visible. |
{
"scoringRule": "Base points per scanned object, plus bonus points when ...",
"totalObjects": 12,
"guestCount": 240,
"leaderboard": [
{
"rank": 1,
"guestId": "uid123",
"displayName": "Jane Doe",
"company": "Acme Labs",
"score": 85,
"basePoints": 60,
"bonusPoints": 20,
"manualAdjustment": 5,
"foundCount": 6,
"totalObjects": 12,
"bonusesAwardedOnSimilarity": ["Main stage banner"]
}
]
}
How the score is calculated
For each object an attendee scanned: the object’s points, plus its bonusPoints if the submitted answer matches. Then the guest’s manual bonusScore adjustment is added.
A bonus counts as correct when the answer matches exactly, or when it is close enough - a Dice bigram similarity above 0.9, so a small typo still earns the bonus.
This is the same rule the attendee app and the organizer console both apply, so all three show the same total. Any bonus that passed on similarity rather than an exact match is listed per guest under bonusesAwardedOnSimilarity, so you can see which answers were graded leniently before awarding a prize on them.
By default the leaderboard only includes guests whose profile is visible, matching the console.