Pocketsflow
All posts
Guides

Pocketsflow Webhooks Explained: Events, Signatures and Retries

Chain7 min read

Apply it with your AI

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.

Pocketsflow core webhook events by area
051015OrdersCustomersProductsReviewsSubscriptions
Pocketsflow core webhook events by area
PointEvents
Orders2
Customers1
Products3
Reviews1
Subscriptions12

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 to past_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:

HeaderWhat it holds
X-Pocketsflow-Signature-V2t=<unix seconds>,v1=<hex>, the HMAC-SHA256 of t, a dot and the raw body. Use this one.
X-Pocketsflow-SignatureLegacy: HMAC-SHA256 of the raw body only
X-Pocketsflow-EventThe event type, such as order.completed
X-Pocketsflow-Event-IdA unique evt_… id, the same on every retry
X-Pocketsflow-TimestampWhen 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

  1. Read the raw body as bytes before any JSON parsing. In Express, use express.raw({ type: "application/json" }) on the webhook route.
  2. Split X-Pocketsflow-Signature-V2 on the comma into t and v1.
  3. Reject the request if t is more than 5 minutes from your clock.
  4. Compute HMAC-SHA256 of t, a dot and the raw body with your secret, and hex encode it.
  5. Compare it to v1 in constant time. Answer 400 if they differ.
  6. 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 marked test: true to 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.

Start selling today.

Sell your first product in minutes, keep more of every sale, and let the AI you already use run the busywork.

Or start from the AI you already use