Webhook Signature Verification
When you configure a webhook secret for a non-Stripe donation platform, Benecaster verifies incoming webhook payloads before logging the donation. This page explains how to obtain each platform’s credential and how verification behaves once it’s configured.
Stripe donations are verified separately via Stripe’s own HMAC signature mechanism — this page covers Ko-fi, PayPal, and Buy Me a Coffee only.
Obtaining Your Platform Credentials
Ko-fi
- Log in to Ko-fi and go to More → API.
- Under Webhook URL, find the Verification Token field.
- Copy the token and paste it into Settings → Listener Support → Webhooks → Ko-fi verification token in Benecaster.
Ko-fi sends the token in an X-KoFi-Token header on every webhook request. Benecaster verifies it with a constant-time string comparison.
PayPal
- Log in to the PayPal Developer Dashboard.
- Open My Apps & Credentials and select your app.
- Under Webhooks, locate the webhook you configured for your podcast site.
- Copy the Webhook ID (not the full URL — just the ID string).
- Paste it into Settings → Listener Support → Webhooks → PayPal webhook ID in Benecaster.
PayPal signs requests using HMAC-SHA256(request_body, webhook_id) and sends the result (base64-encoded) in a PAYPAL-TRANSMISSION-SIG header. Benecaster recomputes the signature and compares.
Buy Me a Coffee
- Log in to Buy Me a Coffee and go to Extras → Webhooks.
- Under your webhook configuration, find the Secret field.
- Copy the secret and paste it into Settings → Listener Support → Webhooks → Buy Me a Coffee webhook secret in Benecaster.
Buy Me a Coffee sends the secret in an X-BMAC-Token header. Benecaster verifies it with a constant-time string comparison, the same shape as Ko-fi.
How Verification Behaves Once Configured
Requests with a configured secret are verified. When a webhook arrives from a platform whose secret you’ve saved, Benecaster checks the signature before writing the donation row.
- Verification passes — the donation is logged normally. The
benecaster_donation_webhook_verifiedaction fires. - Verification fails — Benecaster returns HTTP 403 with the error code
signature_invalidand the message “Webhook signature verification failed.” The donation is not logged. Thebenecaster_donation_webhook_rejectedaction fires. A single debug log line is written:[benecaster] webhook verification failed for platform=<canonical> from IP=<hash>(the IP is hashed — raw addresses are never logged).
Requests from platforms without a configured secret are accepted silently. Verification is strictly opt-in. If you haven’t saved a secret for Ko-fi, Ko-fi webhook requests continue to pass through and log donations as before, with no verification and no action fired. The presence of the benecaster_donation_webhook_verified action firing is itself the signal that verification actually ran for a given request.
Platform slug normalization is permissive. Variations like Ko-Fi, ko_fi, kofi, and KoFi all resolve to the same canonical kofi slug internally. You don’t need to match the platform field in your webhook payload to an exact string.
Stripe payloads bypass this path entirely. Stripe webhooks are received and verified at a separate endpoint (/stripe-webhook) using Stripe’s own timestamp-tolerant HMAC path. They do not pass through the donation webhook endpoint and are unaffected by the secrets configured here.
Developer Hooks
Two action hooks let you observe verification outcomes:
benecaster_donation_webhook_verified( string $canonical_platform, string $raw_platform )— fires on successful verification. Only fires when a secret was configured; silent pass-throughs (no configured secret) do not fire this hook.benecaster_donation_webhook_rejected( string $canonical_platform, string $raw_platform )— fires on 403 rejection. Use this to route alerts to Slack, log to an external service, or trigger security monitoring.
See the individual hook pages for signatures and usage examples.