Agent skill
Maxio Webhooks Skill
Receive and verify Maxio (formerly Chargify) webhooks. Use when setting up Maxio webhook handlers, debugging X-Chargify-Webhook-Signature-Hmac-Sha-256 signature verification, or handling subscription billing events like signup_success, payment_success, payment_failure, renewal_success, and subscription_state_change.
Install this skill
npx skills add hookdeck/webhook-skills --skill maxio-webhooks
When to Use This Skill
- How do I receive Maxio (Chargify) webhooks?
- How do I verify the
X-Chargify-Webhook-Signature-Hmac-Sha-256header? - Why does my Maxio webhook signature verification fail?
- How do I parse Maxio's form-encoded
payload[...]=...&event=...body? - Handling
signup_success,payment_success,payment_failure,renewal_success,subscription_state_ change
How Maxio Webhooks Differ
- The body is
application/x-www-form-urlencoded, not JSON:payload[...]=...&event=.... - The signature is the hex HMAC-SHA256 of the raw form body, keyed with the Site Shared Key used as a raw string (not decoded).
- Verify the raw body first, then parse the form. Parsing and re-encoding changes the bytes.
- There is no timestamp in the signature, so use idempotency to handle replays and retries.
Verification (core)
const crypto = require('crypto');
function verifyMaxio(rawBody, signatureHeader, sharedKey) {
if (!signatureHeader || !sharedKey) return false;
const expected = crypto.createHmac('sha256', sharedKey).update(rawBody).digest('hex');
const provided = signatureHeader.trim().toLowerCase();
if (provided.length !== expected.length) return false;
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(provided));
}
// Header: X-Chargify-Webhook-Signature-Hmac-Sha-256
// Docs test vector: key "123", body "payload[chargify]=testing&event=test"
// -> 19826d51b9f866b26eda1f154de192593360f8d0bcb63df8a28540a5dcf733f1
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Common Event Types
| Event | Triggered When |
|---|---|
signup_success | A customer signs up for a subscription |
payment_success | A payment succeeds |
payment_failure | A payment attempt fails |
renewal_success | A subscription renews |
subscription_ | A subscription changes state |
test | You send a test webhook from the Maxio UI |
The event name arrives in the form field event; the data is in nested payload[...] fields. See references/overview.md.
Environment Variables
# Site Shared Key from your Maxio site webhook settings (see references/setup.md)
MAXIO_SHARED_KEY=your_site_shared_key
Local Development
npx hookdeck-cli listen 3000 maxio --path /webhooks/maxio
No account required: the CLI creates a guest account and gives you a tunnel and web UI.
Reference Materials
- references/overview.md — Webhook concepts and events
- references/setup.md — Dashboard configuration and shared key
- references/verification.md — Signature details and gotchas