Agent skill
Fourthwall Webhooks Skill
Receive and verify Fourthwall webhooks. Use when setting up Fourthwall shop webhook handlers, debugging X-Fourthwall-Hmac-SHA256 signature verification, or handling creator commerce events like ORDER_PLACED, DONATION, GIFT_PURCHASE, or SUBSCRIPTION_PURCHASED.
Install this skill
npx skills add hookdeck/webhook-skills --skill fourthwall-webhooks
When to Use This Skill
- How do I receive Fourthwall webhooks?
- How do I verify the
X-Fourthwall-Hmac-SHA256signature? - Why is my Fourthwall webhook signature verification failing?
- How do I handle
ORDER_PLACED,DONATION,GIFT_PURCHASEorSUBSCRIPTION_PURCHASEDevents? - How do I find my Fourthwall webhook secret key?
Verification (core)
Fourthwall signs the entire raw request body with HMAC-SHA256, keyed with your shop's webhook secret key (a UUID-like string, used as its UTF-8 text), and sends the digest base64-encoded in the X-Fourthwall-Hmac-SHA256 header. There is no timestamp and no signed prefix: the signed content is just the body. Use the raw bytes, never re-serialized JSON, and compare timing-safe.
Node:
const crypto = require('crypto');
function verify(rawBody, signatureHeader, secret) {
if (!signatureHeader) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('base64');
try {
return crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
} catch {
return false; // different lengths
}
}
Python:
import base64, hashlib, hmac
def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
if not signature_header:
return False
digest = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).digest()
expected = base64.b64encode(digest).decode("utf-8")
return hmac.compare_digest(expected.encode(), signature_header.encode())
Shop webhooks only. Platform App webhooks use the same algorithm with the
X-Fourthwall-Hmac-Apps-SHA256header and the HMAC key from the app's settings. This skill covers shop webhooks (X-Fourthwall-Hmac-SHA256).
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Fourthwall has no official webhook verification SDK, so verification is manual in every framework. In Express, read the body with express.raw({ type: '*/*' }) so the raw bytes are available whatever content type is sent.
Payload Shape
Every event shares one envelope; the event-specific object is in data:
{
"testMode": false,
"id": "weve_geAva6c1RAuyb9HQxbSlmA",
"webhookId": "wcon_P-VkRfmJTBaC6_Tst22cew",
"shopId": "sh_7ad0c438-beda-4779-a885-0dc325a755c1",
"type": "ORDER_PLACED",
"apiVersion": "V1_BETA",
"createdAt": "2023-07-12T15:05:11.078089+00:00",
"data": {}
}
Dispatch on the body's type field (there is no event-type header). Treat a repeated id as a duplicate: delivery is at-least-once and ordering is not guaranteed. Events sent by the dashboard's Send test notification button have testMode: true.
Common Event Types
Event (type) | Description |
|---|---|
ORDER_PLACED | New order placed and paid |
ORDER_UPDATED | Order status, shipping address or email changed |
GIFT_PURCHASE | Gift card purchased |
DONATION | New donation received |
SUBSCRIPTION_PURCHASED | New membership subscription |
SUBSCRIPTION_CHANGED | Membership changed (e.g. tier change) |
SUBSCRIPTION_EXPIRED | Membership expired |
PRODUCT_CREATED | Product created |
PRODUCT_UPDATED | Product updated |
See references/overview.md for the full list of 21 event types.
Response Requirements
Respond 200 OK within 2 seconds; any other status or a slow response counts as a failed delivery and is retried. Do slow work asynchronously.
Environment Variables
FOURTHWALL_WEBHOOK_SECRET=your_shop_webhook_secret_key # Dashboard > Settings > For developers > Webhooks
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 fourthwall --path /webhooks/fourthwall
Reference Materials
- references/overview.md - Fourthwall webhook concepts, event types, payload
- references/setup.md - Dashboard and API configuration, secret key
- references/verification.md - Signature verification details and gotchas