Gareth Wilson Gareth Wilson

Guide to FastSpring Webhooks: Features and Best Practices

Published


FastSpring webhooks notify your systems about commerce activity: an order completes, a subscription activates, a subscription is canceled. If you're building on FastSpring, webhooks are how you react to sales and subscription events without polling.

This guide covers how FastSpring webhooks work, the batched event format, how to verify the X-FS-Signature, deduplication, and the best practices for production.

What are FastSpring webhooks?

FastSpring webhooks are HTTP POSTs delivered to endpoints you configure. Each POST is a JSON object with an events array that batches multiple events per request. FastSpring signs the whole delivery with an X-FS-Signature header: a base64 HMAC-SHA256 of the raw body, keyed with the per-webhook "HMAC SHA256 Secret". Signing is only active when you set that secret.

FastSpring webhook features

FeatureDetails
ConfigurationDeveloper Tools > Webhooks > Configuration (per-webhook HMAC secret)
Signature headerX-FS-Signature
Signature schemebase64 HMAC-SHA256 of the raw body, keyed with the per-webhook secret
SigningOnly active when the secret is set
PayloadJSON with a batched events array
DeduplicationEach event has an id; auto-retries reuse it (manual retries get new ids)
RetriesAuto-retries until your endpoint returns HTTP 200 (HTTPS required)
Source IPOptional: 107.23.30.83
SDKNone

Common events

FastSpring events are dotted and cover orders and subscriptions:

EventFires when
order.completedAn order completes
subscription.activatedA subscription activates
subscription.canceledA subscription is canceled
subscription.charge.completedA subscription charge completes
return.createdA return is created

Each item in the events array has its own type and id. Consult FastSpring's webhook reference for the full list.

Setting up FastSpring webhooks

Configure webhooks under Developer Tools > Webhooks > Configuration and set the "HMAC SHA256 Secret" (signing is only active once it's set). Endpoints must be HTTPS; optionally allowlist FastSpring's source IP. FastSpring auto-retries until your endpoint returns HTTP 200.

Securing FastSpring webhooks

Verify the delivery once against the whole raw body, then iterate the events array. The X-FS-Signature header is a base64 HMAC-SHA256 of the raw request body, keyed with the per-webhook secret. Do not parse and re-serialize before verifying.

const crypto = require("crypto");

const SECRET = process.env.FASTSPRING_HMAC_SECRET; // per-webhook

function verify(rawBody, signature) {
  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(rawBody)
    .digest("base64");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature || "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  if (!verify(req.body, req.headers["x-fs-signature"])) {
    return res.sendStatus(401);
  }

  res.sendStatus(200); // acknowledge fast (retries continue until a 200)
  const { events } = JSON.parse(req.body);
  for (const event of events) processQueue.add(event); // dedupe on event.id, async
});

The same check in Python:

import base64
import hashlib
import hmac
import os

SECRET = os.environ["FASTSPRING_HMAC_SECRET"].encode()


def verify(raw_body: bytes, signature: str) -> bool:
    digest = hmac.new(SECRET, raw_body, hashlib.sha256).digest()
    expected = base64.b64encode(digest).decode()
    return hmac.compare_digest(expected, signature or "")

FastSpring webhook limitations and pain points

Batched events, one signature

The Problem: Each POST batches multiple events in events[], but there's one signature over the whole body. Verifying per-event (or assuming one event per request) is wrong.

Why It Happens: FastSpring batches events for delivery efficiency and signs the whole payload.

Workarounds:

  • Verify once over the raw body, then iterate events and process each item.

How Hookdeck Can Help: Hookdeck verifies the signature and can split the batch into individual events, so your app processes one clean event at a time.

Signing is opt-in

The Problem: If you don't set the HMAC secret, deliveries are unsigned and any POST to the URL looks legitimate.

Why It Happens: FastSpring only signs when a secret is configured.

Workarounds:

  • Set the secret and reject deliveries that don't verify; keep the URL secret and HTTPS-only.

How Hookdeck Can Help: Hookdeck gives you a dedicated ingestion URL and can enforce its own verification in front of your endpoint.

Retries reuse the event id

The Problem: FastSpring auto-retries until it gets a 200, and automatic retries reuse the same event id, so the same event arrives repeatedly (manual retries get new ids).

Why It Happens: At-least-once delivery favors eventual delivery.

Workarounds:

  • Dedupe on the event id for automatic retries, and make side effects idempotent.

How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so retries don't double-process. See our guide to webhook idempotency.

Retries continue until a 200

The Problem: Any non-200 keeps FastSpring retrying, so a handler that returns 500 on a processing error triggers repeated deliveries.

Why It Happens: FastSpring treats non-200 as "not delivered".

Workarounds:

  • Return 200 once the signature verifies and the batch is safely enqueued; handle processing errors internally.

How Hookdeck Can Help: Hookdeck returns success to FastSpring and retries to your downstream on its own schedule, so a transient error doesn't cause a retry storm.

Best practices

Verify once over the raw body, then iterate

Compute base64 HMAC-SHA256 over the raw body with the per-webhook secret, compare in constant time, then process each item in events.

Set the secret

Configure the HMAC secret so deliveries are signed, and reject unsigned or invalid ones.

Acknowledge with 200, process asynchronously

Return 200 once verified and enqueued, and handle processing failures internally. See why to process webhooks asynchronously.

Dedupe on event id

Dedupe on each event's id so automatic retries don't double-process.

Make FastSpring webhooks production-ready

Hookdeck verifies X-FS-Signature, splits batches, deduplicates, and durably queues every commerce event

Conclusion

FastSpring webhooks batch multiple events in an events[] array under a single X-FS-Signature (base64 HMAC-SHA256 over the raw body, per-webhook secret). Verify once over the raw body, iterate the batch, set the secret so deliveries are signed, dedupe on event id, and return 200 to stop retries.

Hookdeck verifies the signature, splits batches, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique commerce events.

Get started with Hookdeck for free and handle FastSpring webhooks reliably in minutes.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.