Skip to content

Overview

Payments provides provider-neutral records around Stripe Checkout and PayPal Checkout. It supports one-off checkout, donations, paid downloads, and fulfilment-backed access; Stripe also supports subscriptions and authenticated billing-portal sessions.

Run the package migrations and its settings migration. Choose the runtime provider with CAPELL_PAYMENTS_PROVIDER (stripe by default); this choice is deployment config. The package registers a settings class and schema but does not currently declare a management UI for them in Extensions.

For Stripe, configure the secret and publishable keys plus the webhook signing secret, then register POST /capell/payments/stripe/webhook with Stripe. For PayPal, configure the client ID and secret and set PAYPAL_WEBHOOK_ID, then register POST /capell/payments/paypal/webhook. The PayPal webhook ID is not included in the registered settings schema. Use sandbox API URLs and credentials together; the package derives PayPal live/test state from that URL.

Environment/config values take precedence over stored Payments settings. If an environment value is present, changing the matching stored setting has no effect until the deployment config is changed. Keep provider credentials out of support exports and restrict settings-database and backup access according to your secret-management policy.

Both webhook routes are CSRF-exempt and rate-limited, but provider signatures are verified before an event is accepted. Stripe intake requires the raw signed payload; PayPal calls its verification API and returns a retryable service-unavailable response when verification cannot be completed.

Keep queue workers running. Verified Stripe events are placed on the configured queue (default payments), attempted three times, and deduplicated for one hour. PayPal processing uses the default queue, attempts five times, and backs off for 10, 60, 300, then 900 seconds. Ensure workers consume both queues when they differ.

Webhook IDs are recorded idempotently before queued processing. Checkout fulfilment is also recorded so an already fulfilled session is not fulfilled again; a recorded failed fulfilment can be retried. Unsupported Stripe event types are marked ignored rather than treated as failures.

Use Webhook events to inspect received, processed, ignored, and failed events and their safe error summaries. The package does not schedule its recovery commands:

  • capell:payments:webhooks:reconcile reports counts and exits unsuccessfully when failed events or received events older than 30 minutes remain.
  • capell:payments:webhooks:reprocess synchronously retries up to 100 failed events, or one --event-id. Correct credentials, queue, provider data, and fulfilment configuration first; a named event can be reprocessed regardless of its former status.

Diagnostics also warns about failed fulfilment, unresolved disputes, missing Stripe secrets, and stale webhook delivery (48 hours by default).

Under Monitoring, use:

  • Customers for provider customer IDs and owner/email links.
  • Checkout sessions for purpose, totals, provider status, completion, and fulfilment state.
  • Payment intents for charge status and refund entry.
  • Subscriptions for Stripe subscription state and entitlement dates.
  • Refunds and Disputes for provider reconciliation and response status.
  • Webhook events for intake and processing failures.

These resources are read-only apart from the Issue refund action. Reconcile discrepancies in the provider dashboard using the recorded provider IDs; changing a Capell record would not change provider state.

The current refund action calls Stripe only. Use it only on a succeeded Stripe payment intent, even if the table also shows the action on another provider’s successful intent. Leaving amount blank requests a full refund; a partial amount is entered in the currency’s minor units (for example, pence). The provider can still reject an excessive, already refunded, or otherwise ineligible request. Confirm the intent, currency, amount, reason, and provider dashboard state before submitting because the action calls the provider immediately.

Paid-download fulfilment grants a signed link for 60 minutes by default, backed by an entitlement that lasts seven days by default. An expired entitlement returns 410 Gone, an unsigned link is rejected, and a missing file returns 404. Downloads increment their access count and last-downloaded timestamp. Access Gate and other fulfilment handlers decide their own entitlement behaviour.

When Customer Portal is installed, authenticated customers can see matching billing records and open Stripe’s billing portal. PayPal does not provide subscription or billing-portal behaviour in this package.

The package manifest lists view permissions, but the current payment resource policies allow viewing to any authenticated admin-panel user and do not apply site scope. The refund record action adds no package-specific permission or site check. Treat panel membership as the current payment-data and refund boundary, and do not grant admin access to people who must not see global payment records or initiate Stripe refunds.

Provider payloads and webhook bodies are encrypted, as are stored customer and paid-download email addresses. Provider IDs, amounts, currencies, statuses, event types, errors after redaction, access counts, and timestamps remain visible operational data. No payment-history retention or pruning command is provided; define database and backup retention around financial, dispute, tax, fulfilment, and privacy obligations without deleting records still needed for reconciliation.


For how to use Payments, see the admin guide. For developers: see the README.