Skip to main content
@pylonsync/stripe replaces the ~400 lines every Pylon app rewrites when it adds Stripe billing: customer creation, checkout session creation, billing portal, webhook signature verification, plan derivation, and subscription state. One stripe({plans, hooks}) block returns a manifest fragment and handler factories.

Install

Config

Wrapper files

Pylon loads function handlers by file. Create one-line wrappers under functions/:
Create one more wrapper per handler key exposed by billing.handlers (cancelSubscription, restoreSubscription, stripeWebhook, plus the _pylonStripe* internals).

Required env

Webhook endpoint

Configure in Stripe Dashboard → Developers → Webhooks → Add endpoint:
Copy the signing secret (whsec_...). Set it as STRIPE_WEBHOOK_SECRET on your Pylon machine.

Lifecycle hooks

RBAC

The authorizeReference hook gates subscription mutations. Defaults:
  • referenceType: "org": the caller must be the org’s owner or admin.
  • referenceType: "user": the caller must be the user.
  • referenceType: "custom": you must supply your own resolveCustomer hook, which maps referenceId to a Stripe customer ID and creates one if needed. custom has no default authorization, so supply authorizeReference too.

Security

  • Constant-time signature verification with a 5-minute replay window. The Stripe-Signature header can carry multiple v1= signatures (Stripe emits several during a signing-secret rotation). The verifier accepts a match against any of them.
  • URL allowlist derived automatically from PYLON_PUBLIC_URL and PYLON_CORS_ORIGIN. No hardcoded host strings.
  • Three-signal plan resolver: it matches on lookup_key, then nickname, then price ID match. Stripe sometimes omits the first two on webhook payloads.
  • Double-trial guard: a prior Subscription row for the same reference disables the trial period, regardless of plan config.
  • Idempotent webhook upsert via stripeSubscriptionId lookup, so Stripe retries produce the same state.