Stripe integration
Connect your own Stripe account and SoftLicense issues, renews, suspends and revokes licenses from your checkouts and subscriptions. SoftLicense only ever needs a restricted read key, never a secret key.
Setup
- In Stripe, go to Developers → Webhooks and add a destination pointing at the workspace URL shown in Integrations → Stripe. Select these events:
checkout.session.completedinvoice.paidcustomer.subscription.updatedcustomer.subscription.deletedcharge.refunded - Create a restricted API key with read access to Checkout Sessions, Subscriptions, Invoices, Customers, Charges.
- Paste the webhook signing secret and the restricted key into Integrations → Stripe.
- Map each Stripe price to a SoftLicense policy.
What happens
| Stripe event | SoftLicense action |
|---|---|
checkout.session.completed | Looks up the session's line items. For each mapped price, creates (or finds) the customer by email and issues one license per quantity. Subscriptions expire at the billing period end plus the policy grace. The key is emailed if license emails are enabled. |
invoice.paid | Extends the license tied to the subscription to the new period end and reinstates it if it was suspended. |
customer.subscription.updated | past_due, unpaid, paused → suspend. active, trialing → reinstate and refresh the expiry. |
customer.subscription.deleted | Per mapping: revoke immediately or let the license expire at period end. |
charge.refunded | Per mapping: revoke or ignore. Only full refunds count. |
Reliability
- Events are acknowledged immediately, stored with their id (duplicates are dropped) and processed in the background. Every event and its outcome is listed on the Stripe page with a replay button.
- SoftLicense re-fetches sessions, subscriptions and invoices with your key rather than trusting the event body, and handles both pre- and post-2025 Stripe API shapes.
- Unmapped prices are reported as ignored with a one-click “map this price” shortcut.
Testing locally
stripe listen --forward-to localhost:3000/api/integrations/stripe/<workspace-id>
stripe trigger checkout.session.completedUse the whsec_… printed by stripe listen as the signing secret and an rk_test_… restricted key.