← Back to Documentation

Webhooks — the events FlipKey.gg sends your backend

Set your webhook URL and grab your webhook secret on the Webhooks page. Every delivery is a JSON POST signed with X-FlipKey-Signature = HMAC-SHA256(rawBody, webhook_secret) — verify it against the raw request body before trusting anything (the SDKs do this for you; in Express that means express.raw() on the webhook route, not express.json()).

Delivery & retries

Respond 2xx to acknowledge. Anything else is retried with backoff, so make your handler idempotent on the event's id field — a duplicate delivery must not double-grant. Deliveries that keep failing park in a dead-letter state and we alert you (at most one email an hour). The Webhooks page has a Send test button that fires a signed test event at your endpoint.

Event: item_ticket.redeem — grant an item

Fires when a player redeems (burns) an item ticket — giveaway rewards, watch-drop rewards, purchased items. This is the moment you grant the item in-game.

{
  event: "item_ticket.redeem",
  redemption_id,        // idempotency key
  reward_drop_id,       // which item to grant
  item_name,
  flipkey_account_id,   // stable account key — map to your player
  wallet_address,       // same value
  amount,               // units (1)
  burn_tx_hash,         // on-chain burn of the consumed ticket
  connected: true       // connection is a redeem precondition
}

Ack fulfillment (optional but recommended): POST /api/item-tickets/handoff/ack with { redemption_id, receipt } and your API key — it flips the redemption to fulfilled in your dashboard. The Watch-Drop Handoff SDK verifies, parses, and acks in a few lines.

Key Station Plus test

Freebies, items you sell, creator giveaways and watch-drops need your backend to grant the item, so they unlock once you pass the Plus test on the Key Station page. It sends an item_ticket.redeem with test: true and a redemption_id starting plustest_. Don't grant anything for it: verify the signature and ack that redemption_id through POST /api/item-tickets/handoff/ack with your API key within 15 minutes. The Watch-Drop SDK v0.2+ does this for you.

Event: purchase — token mirror

Fires at every license sale mint so your backend can mirror token_id → drop for redemption lookups. Payload: { contract_address, token_id, flipkey_drop_id, platform, region, minted_at }. The Publisher Starter backend handles this out of the box.

Event: freebie.revoked — take back a free bonus

Fires when a license refund settles after the buyer redeemed and received the campaign freebie: a refund you approved, a chargeback, or a Stripe-side refund of a redeemed purchase. FlipKey burns the freebie token if the player still holds it; this event is your cue to remove the in-game item you granted.

{
  event: "freebie.revoked",
  order_ref,
  license_token_id,
  freebie_id,           // your catalog entry
  freebie_token_id,
  wallet,               // the player to un-grant
  reason,               // "publisher_refund" | "chargeback" | "stripe_refund"
  burned_on_chain,      // false = the player already consumed it in-game, or the burn failed
  burn_tx_hash,
  revoked_at
}

Event: item.revoked — take back a paid item

Fires when the payment behind a paid item ticket is reversed: a chargeback, or a refund you issued from your Stripe dashboard. FlipKey burns the item token if the player still holds it, so gate.check stops granting on its own; this event is your cue to remove anything the game already handed out for it.

{
  event: "item.revoked",
  order_ref,
  flipkey_drop_id,      // the item listing
  token_id,
  wallet,               // the player to un-grant
  reason,               // "chargeback" | "stripe_refund"
  burned_on_chain,      // false = the player already consumed it in-game, or the burn failed
  burn_tx_hash,
  revoked_at
}

Event: creator_statements.issued — creator program run

Fires after every creator-program statement run (scheduler or manual) that issued at least one statement. Use it to refresh the earnings page on your own site, or to kick off payouts on your rail — FlipKey computes the numbers and never moves the money.

{
  event: "creator_statements.issued",
  period_start, period_end,   // YYYY-MM-DD
  run_kind,                   // "auto" (scheduler) | "manual"
  statements: [{
    public_id,                // cs-YYYYMM-…  — fetch lines via GET /api/creator-program/statements/:public_id
    creator_id, creator_name,
    status,                   // "finalized" (pay it) | "carried" (under your minimum, rolls forward)
    payable_cents             // may be negative after refunds — carries to the next statement
  }]
}

Pull the white-label version for your site with GET /api/creator-program/export?period=YYYY-MM, and close a statement once paid with POST /api/creator-program/statements/:public_id/paid { paid_ref }.