Pocketsflow Webhooks Explained: Events, Signatures and Retries
Pocketsflow webhooks send a signed JSON POST to your HTTPS endpoint the moment something happens in your store: a sale completes, an order is refunded, a subscription renews or fails. Pocketsflow signs each delivery with HMAC-SHA256 in the X-Pocketsflow-Signature-V2 header, retries failed deliveries, and keeps a 30 day log you can re-send from.
The Pocketsflow webhook events
Pocketsflow lists 19 core webhook events on its developers page. Most of them cover subscriptions, because a subscription has a long life: activation, renewals, failed charges, pauses and the end. One time sales need only two: order.completed and order.refunded.
| Point | Events |
|---|---|
| Orders | 2 |
| Customers | 1 |
| Products | 3 |
| Reviews | 1 |
| Subscriptions | 12 |
Source: Pocketsflow developers page (www.pocketsflow.com/developers) and webhook docs, November 2026.
That is 12 subscription events, 3 product events, 2 order events, 1 customer event and 1 review event. The full Pocketsflow event catalog in the docs adds more areas: subscription retention, credits, usage billing, memberships, payment plans, courses and payouts. You only receive the events you subscribe to.
order.completed: fulfil the purchase and grant access.customer.subscription.created: fires once, when a subscription activates. Provision the account here.invoice.payment_succeeded: a first charge or a renewal went through. Keep access on.invoice.payment_failed: the subscriber moves topast_due. Start your dunning email.customer.subscription.deleted: revoke access.
How Pocketsflow signs a webhook
Each Pocketsflow endpoint has its own signing secret, 48 hex characters, returned when you create the endpoint. Every delivery carries these headers:
| Header | What it holds |
|---|---|
X-Pocketsflow-Signature-V2 | t=<unix seconds>,v1=<hex>, the HMAC-SHA256 of t, a dot and the raw body. Use this one. |
X-Pocketsflow-Signature | Legacy: HMAC-SHA256 of the raw body only |
X-Pocketsflow-Event | The event type, such as order.completed |
X-Pocketsflow-Event-Id | A unique evt_… id, the same on every retry |
X-Pocketsflow-Timestamp | When the attempt was sent, in milliseconds. Not signed. |
The V2 signature binds a timestamp to the body, so a captured request can't be replayed later. The legacy header is still sent on every delivery so older Pocketsflow integrations keep working, but new code should verify V2.
Verify a Pocketsflow webhook signature
- Read the raw body as bytes before any JSON parsing. In Express, use
express.raw({ type: "application/json" })on the webhook route. - Split
X-Pocketsflow-Signature-V2on the comma intotandv1. - Reject the request if
tis more than 5 minutes from your clock. - Compute HMAC-SHA256 of
t, a dot and the raw body with your secret, and hex encode it. - Compare it to
v1in constant time. Answer400if they differ. - Skip the event if you already handled its event id. Otherwise record the id, then process.
This is the Node.js function from the Pocketsflow docs:
import crypto from "crypto";
const TOLERANCE_SECONDS = 5 * 60;
function verifyWebhookV2(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
(signatureHeader || "").split(",").map((part) => part.split("=", 2)),
);
const timestamp = Number(parts.t);
if (!Number.isInteger(timestamp) || !parts.v1) return false;
const age = Math.abs(Math.floor(Date.now() / 1000) - timestamp);
if (age > TOLERANCE_SECONDS) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.`)
.update(rawBody)
.digest("hex");
const a = Buffer.from(parts.v1, "utf8");
const b = Buffer.from(expected, "utf8");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Never verify a re-serialized copy of the parsed JSON. Key order or spacing can change, and the Pocketsflow signature then fails on a genuine request.
Pocketsflow webhook retries
Pocketsflow gives each attempt 15 seconds. If your endpoint answers 5xx or 429, times out, or can't be reached, Pocketsflow retries up to 4 attempts in total, about 10 seconds, 1 minute and then 5 minutes apart. A 2xx is success, and any other 4xx is final. So answer 200 as soon as you have verified and queued the event, and do slow work afterwards.
After 5 failed events in a row, Pocketsflow emails the store owner. If the endpoint keeps failing for 3 days and at least 20 events in a row, Pocketsflow pauses it. Fix it, then turn it back on in the dashboard or with PATCH /webhooks/{id} and active: true. Missed deliveries stay in the log for 30 days and can be re-sent with POST /delivered-webhooks/{id}/redeliver.
Idempotency for Pocketsflow webhooks
A Pocketsflow event can reach you more than once: a timed out attempt may already have been processed, and you can redeliver by hand. Every copy carries the same event id, so store the ids you have handled and skip repeats. For business logic, also key on a stable value: the order id for order.completed, the pay_… payment id for invoice events.
One exception matters. customer.subscription.updated fires many times over a Pocketsflow subscription's life, so never dedupe it on the customer id. Treat it as a state sync and upsert the status from the payload. Events can also arrive out of order, so don't rely on sequence.
Create and test a Pocketsflow webhook from Claude
Pocketsflow's MCP server has 6 webhook tools, including create_webhook and test_webhook. Connect Claude, ChatGPT or Cursor to https://www.pocketsflow.com/mcp, then paste:
- "Create a Pocketsflow webhook to https://example.com/webhooks/pocketsflow for order.completed and order.refunded." The AI calls
create_webhook, and the reply holds the signing secret. Put it in your server's environment straight away. - "Send a test event to that webhook and tell me the status code." The AI calls
test_webhook, which sends a sample event markedtest: trueto that endpoint only and returns whether it was delivered, the status and the time it took. - "List my webhooks and which events each one gets." The AI calls
list_webhooks; secrets are never in that list.
Webhook endpoints are tied to the mode the account is in when you create them, so a test endpoint only gets test sales. Keep a separate endpoint and secret for live. For the code side, start with the Pocketsflow API quickstart; to choose between the two, read MCP vs API for selling online; and see the Pocketsflow developers page for the core event list.