Agent skill

Creem Webhooks Skill

Receive and verify Creem webhooks. Use when setting up a Creem webhook endpoint, verifying the creem-signature header (hex HMAC-SHA256 of the raw body), debugging signature failures, or handling events like checkout.completed, subscription.paid, refund.created and dispute.created.

Install this skill

npx skills add hookdeck/webhook-skills --skill creem-webhooks


Creem is a merchant-of-record payments platform for SaaS. Its webhooks push checkout, subscription, refund, dispute and customer-credit events to your HTTPS endpoint as JSON POST requests. Each request carries a creem-signature header: a hex HMAC-SHA256 of the raw request body, keyed with the endpoint's signing secret.

When to Use This Skill

  • How do I receive Creem webhooks?
  • How do I verify the creem-signature header?
  • How do I handle checkout.completed, subscription.paid or refund.created events?
  • Why is my Creem webhook signature verification failing?
  • How do I make my Creem webhook handler idempotent?

Verification (core)

creem-signature is the bare lowercase hex HMAC-SHA256 of the raw request body: no prefix, no timestamp, no other header is signed. The key is the signing secret used as a UTF-8 string (not hex- or base64-decoded). Check the header is exactly 64 hex characters before decoding, because Buffer.from(x, 'hex') silently drops invalid characters.

const crypto = require('crypto');

function verifyCreemSignature(rawBody, signature, secret = process.env.CREEM_WEBHOOK_SECRET) {
  if (!secret || typeof signature !== 'string') return false;
  if (!/^[0-9a-f]{64}$/i.test(signature)) return false;   // also guards the hex decode
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
  return crypto.timingSafeEqual(expected, Buffer.from(signature, 'hex'));
}

// rawBody: Buffer from express.raw({ type: '*/*' }); signature: req.headers['creem-signature']

Return 401 when this fails, 400 for a body that isn't a JSON object, and 200 once handled. In Python use hmac.compare_digest on bytes (encode both sides) so a non-ASCII header gives 401, not 500. Creem also ships verifyWebhookSignature in its TypeScript SDK (creem/webhooks); the examples verify manually so the same check works in Express, Next.js and FastAPI. Details in references/verification.md.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Setup

Register the endpoint on the Developers tab of the Creem dashboard (or with POST /v1/webhooks, the SDK, CLI or MCP server) and copy the signing secret from the Developers > Webhook page into CREEM_WEBHOOK_SECRET. Full steps in references/setup.md.

Payload and Event Types

Every payload has a top-level id (evt_...), eventType, created_at (milliseconds) and the resource under object; object.object names the kind (checkout, subscription, ...). Dispatch on eventType; no header names the event.

eventTypeTriggered When
checkout.completedA checkout finishes
subscription.paidA subscription payment succeeds (Creem recommends it for granting access)
subscription.activeA new subscription is created and paid (use for synchronisation)
subscription.canceledThe merchant or customer canceled the subscription
subscription.scheduled_cancelCancellation is scheduled for the end of the period
subscription.past_due / subscription.unpaidA payment failed
subscription.expiredThe period ended without a new payment
subscription.update / subscription.trialing / subscription.pausedThe subscription changed
refund.createdA refund is created
dispute.createdA dispute is opened
credits.granted / credits.consumed / credits.auto_rechargedCustomer credits change
customer_credits.exhaustedA customer's credits ran out during prepaid usage settlement

More detail in references/overview.md.

Delivery and Idempotency

Creem makes up to 5 attempts (initial, then after 30 s, 5 min, 30 min and 6 h) and stops after 24 hours. Delivery is at least once, so deduplicate on the event id. Events can also be resent from the dashboard.

Environment Variables

CREEM_WEBHOOK_SECRET=your_creem_webhook_secret   # Developers > Webhook page

Local Development

npx hookdeck-cli listen 3000 creem --path /webhooks/creem

No account required. Register the printed URL as a webhook endpoint in the Creem dashboard.

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 12, 2026

View on GitHub →