Listener Support Stripe Settings REST API
REST endpoints for reading and writing Stripe-mode configuration and non-Stripe donation webhook secrets. All endpoints require manage_options + a valid X-WP-Nonce header.
GET /benecaster/v1/listener-support/stripe
Returns the current Stripe-mode configuration and the saved state of the three non-Stripe webhook secrets.
Auth: manage_options + X-WP-Nonce
Response:
{
"intended": true,
"mode": "live",
"public_key": "pk_live_...",
"secret_key_set": true,
"webhook_secret_set": true,
"webhook_url": "https://example.com/wp-json/benecaster/v1/stripe-webhook",
"donor_data_retention_days": 0,
"turnstile": {
"site_key": "0x4AAA...",
"secret_key_set": true,
"enabled": true,
"half_configured": false
},
"donation_webhook_secrets": {
"kofi_set": true,
"paypal_set": false,
"bmac_set": false
}
}
Field reference:
| Field | Type | Description |
|---|---|---|
intended |
bool |
The operator’s declared intent to collect Stripe donations. Drives the setup reminder; it does not gate whether donations are accepted — the presence of keys does. |
mode |
string |
The site default keyset mode, test or live. Discloses which keyset this panel is about to edit; it is not a toggle, and it is not any show’s mode. |
public_key |
string |
The Stripe publishable key (safe to expose). Empty string when not configured. |
secret_key_set |
bool |
Whether a Stripe secret key is saved. The key itself is never returned. |
webhook_secret_set |
bool |
Whether a Stripe webhook signing secret is saved. Never returned in plaintext. |
webhook_url |
string |
The URL to paste into Stripe’s webhook dashboard. Read-only. |
donor_data_retention_days |
int |
Donation retention window in days. 0 retains indefinitely. |
turnstile |
object |
Cloudflare Turnstile state — see below. |
donation_webhook_secrets |
object |
Saved state for the three non-Stripe platform secrets — kofi_set, paypal_set, bmac_set (each a bool). The secrets themselves are never returned. |
The turnstile object:
| Field | Type | Description |
|---|---|---|
site_key |
string |
The saved public site key, echoed as stored. |
secret_key_set |
bool |
Whether a secret is saved. Never returned in plaintext. |
enabled |
bool |
True only when both keys are present. |
half_configured |
bool |
True when exactly one key is present. |
enabled requires both keys, and half_configured exists so an admin screen can say why protection is off. With one key saved, enabled is false, half_configured is true, and donations continue to work normally — a half-filled optional setting must not refuse every donation on the site. Once both keys are present, verification does fail closed.
site_key here is not the same value the public config route returns. This admin route echoes the stored key whatever the configuration state, so the settings screen can show what was pasted. The public GET /shows/{id}/listener-support/config returns an empty string unless Turnstile is fully enabled, so a donation form never renders a challenge widget whose verification would refuse everyone.
POST /benecaster/v1/listener-support/stripe
Saves Stripe-mode configuration and/or non-Stripe webhook secrets. All fields are optional — omitted fields are left unchanged.
Auth: manage_options + X-WP-Nonce
Request body:
{
"intended": true,
"public_key": "pk_live_...",
"secret_key": "sk_live_...",
"webhook_secret": "whsec_...",
"donor_data_retention_days": 0,
"turnstile_site_key": "0x4AAA...",
"turnstile_secret_key": "0x4AAA...",
"kofi_webhook_secret": "my-kofi-token",
"paypal_webhook_secret": "WEBHOOK-ID-FROM-PAYPAL-DASHBOARD",
"bmac_webhook_secret": "my-bmac-secret"
}
Field reference:
| Field | Type | Behavior |
|---|---|---|
intended |
bool |
The operator’s declared intent to collect Stripe donations. |
public_key |
string |
Stored as-is (not encrypted — safe to expose). |
secret_key |
string |
Encrypted at rest via libsodium. Omit to keep current; send empty string to clear. |
webhook_secret |
string |
Encrypted at rest. Written on its own, independently of the key pair. Omit to keep current; send empty string to clear. |
donor_data_retention_days |
int |
Donation retention window in days. Negative values are clamped to 0. |
turnstile_site_key |
string |
Cloudflare Turnstile site key. Stored as-is. |
turnstile_secret_key |
string |
Cloudflare Turnstile secret. Encrypted at rest, same layer as the Stripe secret. Omit to keep current; send empty string to clear. |
kofi_webhook_secret |
string |
Ko-fi verification token. Encrypted at rest. Omit to keep current; send whitespace-only to clear. |
paypal_webhook_secret |
string |
PayPal Webhook ID. Encrypted at rest. Omit to keep current; send whitespace-only to clear. |
bmac_webhook_secret |
string |
Buy Me a Coffee webhook secret. Encrypted at rest. Omit to keep current; send whitespace-only to clear. |
The key pair is written into the site default mode’s keyset, so this route can never write into a show’s override. A save here can return benecaster_stripe_key_prefix_mismatch rather than 200 — most often on an install holding a live secret key in the retired mode-less slot while the site is in test mode, where the key cannot be promoted into the test keyset and the save says so rather than blanking it.
Omit-to-preserve, whitespace-to-clear semantics: For all secret fields, omitting the key from the request body leaves the stored credential unchanged. Sending an empty string or a whitespace-only string clears it. This lets the admin UI load without pre-filling password fields and still preserve secrets the user hasn’t intentionally changed.
Response: The saved state in the same shape as GET /stripe (no plaintext secrets).
Example — save only Ko-fi token, leaving everything else untouched:
{
"kofi_webhook_secret": "MY-KOFI-VERIFICATION-TOKEN"
}
Example — clear the PayPal webhook ID:
{
"paypal_webhook_secret": ""
}
GET /benecaster/v1/listener-support/amounts
Returns the donation amount configuration — currency, suggested amounts, whether a supporter may type their own figure, and the floor a typed figure must clear.
This is a separate concern from the routes above, which own Stripe credentials. Three controllers share the one admin tab: credentials, amounts, and link-mode prompt copy.
Auth: manage_options + X-WP-Nonce
Query parameters:
| Parameter | Type | Description |
|---|---|---|
show_id |
int |
Optional. When present and positive, the response also carries a show block for that show. |
Response:
{
"site": {
"currency": "USD",
"suggested_amounts": [500, 1000, 2500],
"allow_custom_amount": true,
"minimum_custom_amount": 100
},
"defaults": {
"currency": "USD",
"suggested_amounts": [500, 1000, 2500],
"allow_custom_amount": true,
"minimum_custom_amount": 100
},
"show": {
"show_id": 12,
"override_enabled": true,
"overrides": { "suggested_amounts": [300, 700] },
"effective": {
"currency": "USD",
"suggested_amounts": [300, 700],
"allow_custom_amount": true,
"minimum_custom_amount": 100
}
}
}
| Field | Description |
|---|---|
site |
The saved site-wide values. |
defaults |
The shipped defaults, so a screen can offer a reset and show what “unset” means. |
show.override_enabled |
Whether this show uses its own values instead of the site’s. |
show.overrides |
Only the keys this show actually overrides — not a full merged set. |
show.effective |
What the donation form actually enforces for this show. |
All amounts are integers in the smallest currency unit — 500 is $5.00 in USD and ¥500 in JPY.
effective is not site merged with overrides. It is post-filter: it runs benecaster_donation_suggested_amounts and benecaster_donation_minimum_amount. On an install using either filter it disagrees with both site and overrides, and that is the point — a screen showing only saved values would tell the podcaster something the donation form does not do. Read effective to answer “what will a supporter see”, and site / overrides to answer “what is saved”.
POST /benecaster/v1/listener-support/amounts
Saves the site-wide amount configuration.
Auth: manage_options + X-WP-Nonce
Request body — any of currency, suggested_amounts, allow_custom_amount, minimum_custom_amount. Values are validated and clamped on save, so the response is the authoritative record of what was stored.
{
"currency": "GBP",
"suggested_amounts": [300, 500, 1000],
"allow_custom_amount": true,
"minimum_custom_amount": 200
}
Response: 200 — { "site": { … }, "defaults": { … } }, carrying the saved values as stored rather than as submitted.
POST /benecaster/v1/listener-support/amounts/show/{id}
Saves per-show overrides.
Auth: manage_options + X-WP-Nonce
Request body:
| Field | Type | Behavior |
|---|---|---|
override_enabled |
bool |
Whether this show uses its own values. |
overrides |
object |
Same keys as the site configuration. |
With override_enabled set to false the stored overrides are retained but ignored, so a show can be switched back to site defaults and back again without retyping them.
Response: 200 — { "show": { … } }, the same show block GET returns, effective included.
Errors: benecaster_invalid_show (400) when the ID is not a positive integer.
See Also
Need this built rather than just documented? See our services →