# Stripe payments (BYOK) HarborFM does not process payments with a platform Stripe account. Eligible show owners connect **their own** Stripe keys (**bring your own key**), publish plans, and sell access. Listeners pay via Stripe Checkout and receive a **private RSS** access token. Secrets are encrypted with the same secrets key used for exports (`HARBORFM_SECRETS_KEY` / `SECRETS_DIR`). For restricted-key permissions, webhook event tables, and local Stripe CLI setup, see the main [README](../blob/main/README.md) "Stripe payments" section. ## Who can use it - **`defaultCanStripe`** (Settings > Default Limits): whether newly registered users get Stripe access. Default is on. See [Admin and settings](Admin-and-settings.md#global-settings). - **`canStripe`** (Users admin): per-user flag. When off, that user cannot open Stripe Payments or call Stripe API routes. - On a show, **managers** can attach an existing owner credential pack and toggle payments. Only the **owner** can create, edit, or delete credential packs. Stripe access is an account flag, not a show role. See [Podcasts: Collaborators](Podcasts.md#collaborators-and-permissions). ## Credential packs (test and live) Under the show’s **Payments** UI, create a Stripe account pack: 1. Display name 2. Mode: **test** or **live** (fixed for that pack; create a second pack to use the other mode) 3. Restricted secret key (`rk_test_…` / `rk_live_…` preferred), publishable key, and webhook signing secret (`whsec_…`) 4. Optional verify step that probes Write permissions HarborFM needs Attach one pack to the show and enable **Accept Stripe payments on this show**. Use **Pause new subscriptions** to block Checkout while you edit plans or coupons (existing subscribers keep access). The same pack can be reused on multiple shows owned by that user. Test and live plans/coupons are separate. **Webhook URL** (copy from Payments): ```text https:///api/public/stripe/webhook/ ``` Locally, use the Stripe CLI (`pnpm stripe:listen` from the repo) and paste the printed `whsec_…` into the pack. Without valid webhooks, Checkout success may still claim once, but renewals and cancellations will not stay in sync. The credential wizard lists the restricted-key **Write** permissions and the webhook events HarborFM needs (select only those events in Stripe, not Select all). Full tables are in the main [README](../blob/main/README.md). ## Plans and billing cycle Plan kinds: **Monthly**, **Yearly**, and **One-time**. At most one **active** plan per kind per show mode. To change a price, deactivate the current plan and add a new one for that kind (existing subscribers stay on their Stripe price). You can reactivate a deactivated plan only when no other active plan of that kind exists. Recurring plans support **auto-renew by default**. Deleting a recurring plan cancels its active subscriptions in that mode and revokes access. Deleting a one-time plan archives the Stripe product but does not revoke past one-time purchases. **Billing cycle** (per show): - **Anniversary** (default): renews on the signup anniversary (Stripe default). - **Month Start**: Checkout anchors recurring billing to the 1st of the month (Stripe may prorate the first stub period). Active-subscriber stats in Payments show per-kind revenue. ## Checkout and access tokens Listeners subscribe from the public feed (**Subscribe**). Checkout creates a Stripe session; after payment, HarborFM fulfills via webhook (`checkout.session.completed`) and/or the success page claim. - Success URL reveals the **access token** and **private RSS** URL once (`/feed/{slug}/subscribe/success?session_id=…`). - Private feed path is under `/api/public/podcasts/{slug}/private/{token}/rss` (token prefix from `SUBSCRIBER_TOKEN_PREFIX`, default `hfm_sub_`). - Refreshing or reclaiming the same session does not show the full token again; listeners can use **Manage Subscription > Recover token** (email) if needed. - Active coupons enable promotion codes on Checkout. See [Public feeds and embed](Public-feeds-and-embed.md#paid-access-and-private-rss). ## Manage subscription (listeners) From the feed **Manage Subscription** dialog (cookie or pasted token / private RSS URL): | Action | Notes | |--------|--------| | Manage billing | Stripe Customer Portal (recurring) | | Turn off auto-renew | Cancel at period end; access continues until period end | | Renew / keep auto-renewing | Undo cancel-at-period-end, or pay a past-due invoice | | Regenerate access token | Issues a new token (cooldown applies); old token stops working | | Request refund | Owner reviews under Payments > Refund requests | | Recover token | Emails access details when email delivery is configured (cooldown applies) | Owners approve or deny refund requests in the show Payments UI. Approving refunds in Stripe and revokes the subscriber token. ## Coupons Per show and mode: create percent or fixed-amount coupons with duration once, repeating, or forever. Optional start/end times and max redemptions. Activate or deactivate without deleting. Discount shape is fixed after create. Synced to Stripe Coupons and Promotion Codes. ## See also - [Podcasts](Podcasts.md) - Show Payments entry point and permissions - [Public feeds and embed](Public-feeds-and-embed.md) - Subscribe / Manage Subscription on the feed - [Admin and settings](Admin-and-settings.md) - `defaultCanStripe` and per-user `canStripe` - [Deployment](Deployment.md) - Public host and secrets key for webhooks - Main [README](../blob/main/README.md) - Stripe payments (restricted keys, webhook events, Stripe CLI)