Webhooks
Gemifier never hands a player a catalog item. Your system does. When a player earns or buys one, you receive a webhook telling you to deliver it.
So a 200 from buying an item means the points were
spent. It does not mean the player has the item. That arrives afterwards, over a webhook, and there
is no other way to get it.
What arrives
Four events. One asks you to do something, the other three tell you something happened.
| Event | What your 2xx means |
|---|---|
catalog_item.fulfillment_requested | You have the instruction and will deliver the item. Not that the player has it. |
mission.completed | Nothing. You read it or you do not. |
streak.milestone_reached | Nothing. You read it or you do not. |
leaderboard.period_closed | Nothing. You read it or you do not. |
The three notifications carry no amounts. Anything a mission, a milestone or a leaderboard pays
arrives as its own catalog_item.fulfillment_requested. Points arrive not at all, because Gemifier
moves the balance itself.
The wire shapes are on Events.
Set one up
The Public API cannot create, list, test or replace an endpoint. Open Webhooks in the dashboard and create one. It asks for two things:
- URL. An absolute
httporhttpsaddress, at most 2,048 characters, reachable from the internet. One pointing atlocalhostor a private address is refused. - Events. At least one.
An endpoint belongs to one environment. A Sandbox endpoint never sees Live traffic and you cannot move one across, so going live means a second endpoint with its own secret.
Redirects are not followed. A 301 pointing at your real receiver is a failed attempt, not a
delivery. Register the final URL.
The secret, shown once
Creating an endpoint gives you a signing secret: whsec_ followed by 64 lowercase hex characters.
You see it when you create it and when you replace it, never again.
Keep it the way you keep a password: on your server, never in a client. Replacing it keeps the old one working for 24 hours and signs every delivery with both, so you can deploy the new one without timing anything. See Verifying signatures.
Test it with a ping
Every endpoint has a Ping button. It sends one delivery straight away, signed the way real traffic is, so a green ping proves the thing that matters: your signature check agrees with ours.
A ping is never retried, it ignores what the endpoint subscribes to, and it works on an endpoint you have switched off. Each one carries a new delivery id, so two pings never collapse into one.
Recognise it by X-Gemifier-Event: ping and this body:
{
"version": 1,
"event": "ping",
"deliveryId": "019f0000-0000-7000-8000-0000000000aa",
"occurredAtUtc": "2026-08-19T12:00:00+00:00",
"data": {
"endpointId": "019f0000-0000-7000-8000-000000000010",
"projectEnvironmentId": "019f0000-0000-7000-8000-000000000011",
"message": "This is a test delivery from Gemifier."
}
}message is that same sentence every time, and the body names no player. You cannot subscribe to
ping, so treat an event you do not recognise as something to accept rather than refuse.
One endpoint for rewards
An environment sends catalog_item.fulfillment_requested to one URL. A second endpoint subscribing
to it is refused, and the refusal names the one already holding it. Two systems told to hand over
the same reward cannot tell that the instruction is a repeat.
The three notifications go to as many endpoints as you like.
What there is not
- No delivery log. The dashboard shows what is waiting and what was given up on, not every delivery ever made. For why one failed, open the player and read their reward.
- No replay by delivery id. You can send everything an environment gave up on again, or everything for one reward. See Retries.
- No catch-up. An event that happens while nothing is subscribed is not delivered later. Subscribe before you rely on it.
- No
User-Agent. Gemifier sets none. Do not filter on one.