PokeIndie integrations
Three focused integration silos for automating release notes, connecting verified pokes to in-game rewards, and bringing configured games into your Discord community.
Integration 01
Changelog Hook
PokeIndie pulls a public JSON feed every 12 hours, deduplicates entries, stores them locally, and publishes them in the game’s year/month changelog archive.
# Game token
Open Dashboard → Games → Edit → Links and copy the public game token. It identifies the listing but is not a secret or permission to create pokes.
{"game":"7d889576-c166-40ea-8ee3-20f15c49f832"}# Feed schema
Your endpoint may return one object or an array. game, date, and log are required. Title, version, and major status are optional.
[
{
"game": "7d889576-c166-40ea-8ee3-20f15c49f832",
"date": "2026-07-20T18:30:00Z",
"title": "The Forge Update",
"version": "1.4.0",
"major": true,
"log": "Added co-op raids.\nRebalanced iron production.\nFixed save migration."
}
]- Host the JSON on a public HTTP or HTTPS URL.
- Paste it into Changelog JSON feed URL.
- Save the game listing.
- New entries appear after the next scheduled synchronization.
# Delivery, limits, and retries
- Feeds run at 01:00 and 13:00 server time.
- Each log is limited to 50,000 characters; the response is limited to 1 MB.
- A mismatched game token rejects the feed without storing entries.
- Date and log content form the deduplication fingerprint.
- Private, loopback, and internal destinations are blocked.
php artisan changelogs:sync --game=7d889576-c166-40ea-8ee3-20f15c49f832
php artisan schedule:workIntegration 02
Poke Reward Hook
Send a player through a simple PokeIndie reward link, preserve their opaque game account ID through registration, and receive POST callbacks for website and Discord pokes.
# Create the player reward link
- Set an HTTPS Poke callback URL and save the game.
- Redirect the player to the game’s poke URL with your opaque player ID as
user_id. - PokeIndie stores the value in an encrypted, HTTP-only cookie for 180 days, so registration and login redirects do not lose it.
- When that browser account pokes the game, the POST callback contains the same player ID.
$gameSlug = 'your-game-slug';
$playerId = 'player_84920';
$url = 'https://pokeindie.com/games/'.$gameSlug.'/poke?'.http_build_query([
'user_id' => $playerId,
]);
header('Location: '.$url);The player attribution value is intentionally not authenticated by PokeIndie. Treat it only as an opaque identifier and decide on your own backend whether it is eligible for a reward. Never put email addresses, access tokens, or sensitive personal information in user_id.
# Callback payloads
Every successful poke source creates a durable event. Website pokes carry the attributed game user ID when available:
{
"event_id": "682c6f40-202a-4af4-84db-72a69eb69f54",
"event": "poke.created",
"game": "7d889576-c166-40ea-8ee3-20f15c49f832",
"game_slug": "your-game-slug",
"poke_id": 9814,
"source": "website",
"count": 33142,
"recipient": {
"type": "developer_user",
"user_id": "player_84920"
},
"occurred_at": "2026-07-20T18:42:10+00:00"
}Discord cannot read the browser attribution cookie, so Discord events provide the member identity for your backend to map:
{
"event_id": "46f688f8-b43c-461e-a9c5-65f7f7647aa2",
"event": "poke.created",
"game": "7d889576-c166-40ea-8ee3-20f15c49f832",
"game_slug": "your-game-slug",
"poke_id": 9815,
"source": "discord",
"count": 33143,
"recipient": {
"type": "discord",
"discord_user_id": "345678901234567890",
"discord_username": "playername",
"discord_display_name": "Player Name"
},
"occurred_at": "2026-07-20T18:45:10+00:00"
}Return any 2xx response after durably accepting the event. PokeIndie retries after 60 seconds and then 5 minutes, for at most three total attempts. Delivery status, response code, and the latest error appear below the game editor.
# Authenticate and process callbacks
Authenticate every callback cryptographically. PokeIndie sends X-PokeIndie-Event, X-PokeIndie-Timestamp, and X-PokeIndie-Signature. The signature is sha256=HMAC_SHA256(timestamp + "." + raw_request_body, signing_secret).
X-Forwarded-For, and informational origin headers can change or be misconfigured. Only a valid HMAC signature made with your game’s private callback secret proves that the payload is authentic.$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_POKEINDIE_TIMESTAMP'] ?? '';
$provided = $_SERVER['HTTP_X_POKEINDIE_SIGNATURE'] ?? '';
if (abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit('Stale callback');
}
$expected = 'sha256='.hash_hmac(
'sha256',
$timestamp.'.'.$body,
$_ENV['POKEINDIE_CALLBACK_SECRET']
);
if (!hash_equals($expected, $provided)) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($body, true, flags: JSON_THROW_ON_ERROR);
// Insert event_id into a UNIQUE column before granting the reward.
// If it already exists, return 204 without rewarding twice.
http_response_code(204);- Use the raw body when verifying; parsing and re-encoding JSON changes the signature.
- Reject timestamps older than five minutes.
- Make
event_idunique in your database so retries cannot grant duplicate rewards. - Map Discord users by immutable
discord_user_id, not username. - Treat all recipient values as identifiers, never authorization credentials.
- Run PokeIndie queue workers in production or callbacks remain pending.
Integration 03
Discord Bot
Connect one Discord server directly to one game. Community members run /poke with no game argument; PokeIndie resolves the game securely from the server.
# Requirements
- An active PokeIndie Premium membership.
- A Discord account linked from your PokeIndie profile.
- Discord server ownership or the Manage Server permission.
- At least one game owned by your PokeIndie account.
- Community members must link their Discord identity to a PokeIndie account before using
/poke.
# Installation
- Open the game in Dashboard → Games and select its Discord tab.
- Connect your Discord account if it is not linked.
- Choose one server where you are owner or have Manage Server.
- Approve the game-bound authorization screen. The state expires after 10 minutes and cannot be reused for a different game or server.
- Move the PokeIndie bot role above every role it may reward, then return to the Discord tab and refresh server data.
# Game, channels, and rewards
- Choose all eligible channels or restrict
/poketo selected channels. - Select rich, compact, or private responses.
- Add up to four reward roles with monthly or lifetime poke thresholds.
- Save and run the safe test. It validates presence, freshness, channels, and role permissions without creating a poke.
{
"interaction_id": "123456789012345678",
"discord_guild_id": "123456789012345678",
"discord_channel_id": "234567890123456789",
"discord_user_id": "345678901234567890"
}The official bot signs this private payload. The backend derives the game from the server, enforces channel and Premium state, prevents interaction replay, applies cooldowns, and records monthly statistics. Developers never send a game token to this endpoint.
# Slash commands
| Command | Status | Behavior |
|---|---|---|
| /poke | Available | Records a poke for the linked member on the game connected to the current server, limited to once every 4 hours per member per game; there is no game option. |
| /game-info <game> | Available | Looks up any published PokeIndie listing by name, with autocomplete suggestions as you type. Not limited to the game connected to this server. Replies with the developer, short description, pricing model, release date, lifetime pokes, and listing link. |
| /game-stats | Available | Shows pokes this month, monthly unique members, and lifetime pokes for the game connected to the current server; there is no game option. |
| /poke-leaderboard | Available | Ranks the top members by pokes this month for the game connected to the current server, mentioning each member. Resets with the monthly period. |
The bot refreshes server health and its global “pokes this month” status every five minutes. Role changes run asynchronously and retry temporary failures. /game-stats and /poke-leaderboard require the same active, Premium-connected server integration as /poke; /game-info works in any server the bot has joined.
# Troubleshooting
Premium integration is inactive
Renew Premium and allow up to 15 minutes for status synchronization. Moderators and administrators bypass this gate for support.
Link your Discord account first
Sign in with Discord or connect it from profile settings; the Discord member must map to a PokeIndie user.
This server requires reconfiguration
A legacy server was linked to zero or multiple games. Open the game Discord tab and explicitly reconnect it; history remains intact.
Command cannot complete in this channel
Choose all eligible channels or select this channel in the game Discord tab, then save.
A reward role is not assignable
Give the bot Manage Roles, move its role above the reward role, refresh server data, and reselect the role.
Poke request was replayed or rate limited
Discord interactions are idempotent and fresh creations have a cooldown. Wait for the indicated interval rather than resending the same interaction.