Skip to main content

Listener Support Donations REST API

REST endpoints for recording and retrieving listener donation references. These endpoints are part of the benecaster/v1 namespace and live on the main yoursite.com WordPress installation — not on updates.benecaster.com.


POST /benecaster/v1/listener-support/donations

Records a donation reference after a listener has donated on an external platform (Ko-fi, PayPal, Buy Me a Coffee, etc.).

Auth: Public — no nonce required. This is intentional: external platforms (Ko-fi, PayPal, Buy Me a Coffee) send webhook-style callbacks without WordPress credentials, so requiring authentication would block them. Cookie authentication is optional: when a logged-in user submits, their user_id is stored with the row; anonymous submissions store user_id = NULL.

Security note: Because this endpoint is public, anyone who knows a valid show_id can submit a fabricated donation reference. This does not represent financial risk — no money changes hands through this endpoint — but it could result in fake records in your donation log and unwanted thank-you emails sent to submitted addresses. Benecaster rate-limits this endpoint per IP. If you do not use the webhook integration (for example, you record donations manually or via the admin), contact support to discuss restricting this endpoint on your installation. For verified, fraud-resistant donations, use Stripe mode instead — Stripe payments are server-verified and cannot be fabricated.

Request body:

{
  "show_id":     1,
  "platform":    "ko-fi",
  "donor_email": "listener@example.com",
  "amount":      12.50,
  "currency":    "USD",
  "reference":   "TX-123ABC",
  "note":        "Love the show, keep it going!",
  "donated_at":  "2026-06-13T14:30:00Z"
}

Field reference:

Field Required Type Notes
show_id Yes int Must reference a published benecaster_show post.
platform Yes string Platform slug, e.g. 'ko-fi', 'paypal', 'buymeacoffee'. No validation against a fixed list — any non-empty string is accepted.
donor_email No string Sanitized via sanitize_email + is_email. Stored null when absent or invalid.
amount No number Non-negative. Stored null when absent.
currency No string ISO 4217 code; uppercased before storage (e.g. "usd""USD").
reference No string Platform transaction ID or order number; max 255 characters.
note No string Supporter-supplied message.
donated_at No string ISO 8601 datetime. Defaults to current_time('mysql') when absent or unparseable.

Success response — HTTP 201:

{
  "id":          42,
  "show_id":     1,
  "user_id":     17,
  "platform":    "ko-fi",
  "donated_at":  "2026-06-13T14:30:00Z",
  "row": { }
}

user_id is null for anonymous submissions. row contains the full inserted row from benecaster_listener_support_donations.

After the row is written, the benecaster_listener_support_donation_logged action fires synchronously. If the submitted donor_email is a valid address, a donation_thank_you email is queued for that address.

Error responses:

HTTP Code Condition
400 show_id or platform is missing from the request body.
403 signature_invalid A webhook secret is configured for this platform and the incoming signature or token failed verification. Body: { "code": "signature_invalid", "message": "Webhook signature verification failed." }
404 show_id does not match a published benecaster_show post.
500 Database insert failure.

GET /benecaster/v1/listener-support/donations

Returns a paginated list of logged donation references.

Auth: manage_options + X-WP-Nonce

Query parameters:

Parameter Default Notes
show_id (none) Filter to a single show. Omit for the site-wide list.
page 1 Page number.
per_page 20 Results per page. Clamped to a maximum of 100.

Response:

{
  "items": [
    {
      "id":         42,
      "show_id":    1,
      "user_id":    17,
      "platform":   "ko-fi",
      "amount":     12.50,
      "currency":   "USD",
      "reference":  "TX-123ABC",
      "note":       "Love the show, keep it going!",
      "donated_at": "2026-06-13T14:30:00Z"
    }
  ],
  "total":    156,
  "page":     1,
  "per_page": 20
}

Rows are ordered by donated_at DESC, id DESC. user_id is null for anonymous submissions. amount, currency, reference, and note are null when not provided at submission time.

Use cases:

  • Building a donor board or “thank-you wall” on your site — pull the list server-side and render it in a template.
  • Syncing donation references to a CRM or analytics platform — poll this endpoint periodically or use the benecaster_listener_support_donation_logged action for real-time sync.
  • Displaying a running donation total — aggregate amount values on the client or in a server-side cron.

Webhook Signature Verification

When a webhook secret is configured for a platform via DonationWebhookSecrets (see Settings → Listener Support), this endpoint verifies the incoming request’s signature or token before writing the donation row.

Per-platform verification mechanism:

Platform Header inspected Verification method
Ko-fi X-KoFi-Token Constant-time string compare against stored token
PayPal PAYPAL-TRANSMISSION-SIG base64(HMAC-SHA256(request_body, webhook_id)) compare
Buy Me a Coffee X-BMAC-Token Constant-time string compare against stored secret

Behavior when a secret is configured:

Behavior when no secret is configured for a platform: Requests are accepted as before — no verification runs, no action fires. Verification is strictly opt-in.

Platform slug normalization: The platform field is normalized before the secret lookup — Ko-Fi, ko_fi, kofi, and KoFi all resolve to the canonical kofi slug. The raw value is preserved in the logged row.

Stripe bypass: Requests with platform=stripe are rejected at this endpoint (Stripe payments process through /stripe-webhook). No verification runs for them here.

See Webhook Signature Verification → for the setup walkthrough and full behavior reference.


Donation Verification

This endpoint records donation references — it does not verify that a payment actually occurred on the external platform. Platforms like Ko-fi and PayPal do not offer a public API to verify individual transactions, and many podcasters use platforms with no API at all.

If you need verified donations (amount confirmed, fraud-resistant), use Stripe mode instead. Stripe mode processes payments directly and records verified transactions automatically.

See Also