Start building
Build

Webhooks

Signed events for launches, payouts, low credit and keys at their limit, as they happen.

Add an endpoint (a public https:// URL) on the dashboard's Webhooks page or with POST /webhooks, for some or all events. The answer carries its signing secret (whsec_...): store it, as only a retry with the same Idempotency-Key shows it again. A project has up to 5 endpoints.

Events

Event When data holds
launch.confirmed A launch the chain confirmed: its token is on its route. launch
launch.failed A launch the chain refused, or whose route came out other than prepared. launch
token.imported An import the chain confirmed: the existing token is on its route. launch
token.graduated A token's curve completed: it trades on PumpSwap, its fees still on its route. token, graduated_at
payout.credited A payout of a token's creator fees became AI credit. payout
account.low_balance An account's spendable credit fell under the threshold: once, until a credit lifts it back. account, threshold_usd
key.limit_reached A router key's call was refused for its spending limit: once in each of the limit's periods. key
route.changed A token's creator fees no longer follow the route Fuel locked (a takeover on pump.fun): its payouts stop. token, reason, detected_at

POST /webhooks/{id}/test sends a ping to one endpoint. Every delivery is a POST with the same envelope. data holds what the event is about, in the API's own shapes:

JSON
{
  "id": "evt_4c9LGfliJda80U3V",
  "type": "payout.credited",
  "created_at": "2026-10-07T13:40:01.000Z",
  "project": "prj_joucOmKkV9Ikdf92",
  "data": {
    "payout": {
      "token": "MASi45ub7Qe4ZE36UT5G6cU4ud8Fhhe4deS4F3cw9KTA",
      "account": "acc_arqp1qhbpvjhzifE",
      "signature": "dYmM6J4tmCUz5J2h...",
      "event": "2.3",
      "slot": "372918466",
      "quote_mint": "So11111111111111111111111111111111111111112",
      "distributed_lamports": "61500000",
      "ai_bps": 5600,
      "ai_lamports": "34440000",
      "sol_usd": { "price": "221.04", "confidence": "0.064", "published_at": "2026-10-07T13:39:58.000Z" },
      "credited_usd": "7.610413",
      "created_at": "2026-10-07T13:40:01.000Z"
    }
  }
}

Its headers name the event too: fuel-event-id, fuel-event-type, and the signature.

Checking a signature

Each delivery carries fuel-signature: t=<unix seconds>,v1=<hex>: the HMAC-SHA256 of <t>.<raw body> under the endpoint's secret. Recompute it over the raw body, compare in constant time, and refuse a t more than 5 minutes from your clock.

TypeScript
import { verifyWebhook } from "@fuelpad/sdk/webhooks";

const event = await verifyWebhook({
  body: await request.text(),
  header: request.headers.get("fuel-signature"),
  // Or [current, previous] while you rotate it.
  secret: process.env.FUEL_WEBHOOK_SECRET!,
});
// event is typed: switch on event.type to read event.data.

Read the body as raw text before parsing it: parsing and serializing again changes the bytes. After POST /webhooks/{id}/rotate, deliveries carry both secrets' signatures for a day.

Delivery

  • Answer 2xx within 10 seconds. Anything else, a redirect included, is a failure.
  • Failures are retried with backoff (1, 5, 15 and 30 minutes, then hourly and longer) for 24 hours.
  • An event can arrive more than once: use its id to do its work once.
  • GET /webhooks/deliveries lists them, and POST /webhooks/deliveries/{id}/replay sends one again.
  • POST /webhooks/{id}/test sends a ping now.