Webhooks · Events
game.completed
Fires once when a user finishes a game. The single most useful webhook event — wire this up first.
When it fires
Every time a user successfully finishes a game in your embed. Pause/restart/abandon do not emit a completion. The event is also produced when scores are submitted to a leaderboard.
Payload
json
{
"event": "game.completed",
"id": "evt_a1b2c3d4e5f6",
"account_id": "acc_acme",
"external_user_id": "u_12345",
"external_username": "alice",
"player_id": "plyr_acme_blog",
"game": "trivia",
"day": "20260506",
"difficulty": "medium",
"score": 950,
"time_ms": 45000,
"moves": null,
"hints_used": 2,
"won": true,
"completed_at": 1715000000
}
Field reference
event"game.completed"
The event type. Always "game.completed" for this event.
idstring
Stable per-event ID. Use for deduplication.
account_idstring
Your Playgent workspace ID.
external_user_idstring | null
The
externalUserId you passed to the SDK, or null.external_usernamestring | null
The
externalUsername you passed to the SDK, or null.player_idstring
The
plyr_… ID this embed used.gamestring
Game ID, e.g.
"trivia".daystring
UTC date in
YYYYMMDD format. Useful for daily-mode leaderboards.difficultystring
Difficulty tier (
easy, medium, hard, or game-specific).scorenumber | null
Game-specific score.
null for games that don't score numerically.time_msnumber
Total play time in milliseconds.
movesnumber | null
Move count for games where it applies (Sudoku, etc.).
null otherwise.hints_usednumber
How many hints the user revealed during play.
wonboolean
Whether the user finished successfully.
completed_atnumber
UNIX timestamp (seconds).
Headers
text
Playgent-Event: game.completed
Playgent-Signature: t=<unix>,v1=<hex>
Content-Type: application/json
User-Agent: Playgent-Webhook/1
Example handler
js
import express from "express";
import crypto from "node:crypto";
const app = express();
app.post(
"/webhooks/playgent",
express.raw({ type: "application/json" }),
async (req, res) => {
const raw = req.body.toString("utf8");
if (!verify(req.headers["playgent-signature"], raw, process.env.PLAYGENT_WHSEC)) {
return res.status(401).end();
}
const event = JSON.parse(raw);
if (event.event === "game.completed") {
await db.completions.upsert({
id: event.id, // dedupe key
userId: event.external_user_id,
score: event.score,
durationMs: event.time_ms,
completedAt: event.completed_at,
});
}
res.status(200).end();
}
);