Documentation
Stripe integration
The shortest path from "your customer hit pay" to "your customer has a working license" is one Stripe webhook configured against KeyStack. This guide takes about 10 minutes.
What it does
When a Stripe checkout.session.completed event fires:
- KeyStack matches the Stripe price/product to a license plan you've configured.
- KeyStack dedupes / creates a customer from the Stripe Customer.
- KeyStack mints a license key using that plan.
- The key is written back as
metadataon the Stripe Customer (so you can see it in the Stripe dashboard). - KeyStack emails the customer with their key (using your branding).
- KeyStack records an
order.createdevent in the audit log.
Step 1 — Add a Stripe key
KeyStack only needs your restricted key with read access to Customers + Charges + Checkout Sessions + write access to Customer metadata. Generate it from Stripe → Developers → API keys → Create restricted key.
In KeyStack: Settings → Billing → Stripe → Connect. Paste the key.
Step 2 — Map prices to plans
For each Stripe price you sell, choose which KeyStack license plan it should mint:
| Stripe Price | KeyStack Plan |
|---|---|
price_pro_monthly | monthly-pro |
price_pro_yearly | yearly-pro |
price_lifetime | lifetime-pro |
You can change this mapping at any time.
Step 3 — Add the webhook in Stripe
In Stripe → Developers → Webhooks → Add endpoint, set:
- URL:
https://api.keystack.dev/v1/webhooks/stripe/<your-org-slug> - Events:
checkout.session.completed,customer.subscription.deleted,charge.refunded
KeyStack will reject events whose signature doesn't match the webhook secret you'll see one screen later — paste that secret into Settings → Billing → Stripe → Webhook secret.
Step 4 — Test with a real test-mode purchase
Use a Stripe test card and complete a checkout. Within 1–2 seconds you should see:
- A new license in the dashboard.
- An email landing in your inbox (Mailhog locally, real provider in prod).
- An entry in the Audit log tagged
order.created.
If something doesn't show up, head to Settings → Webhooks → Deliveries and inspect the failed deliveries. Click Replay to retry.
Advanced
- Sub-products: if a single Stripe checkout maps to multiple keys, configure quantity-based plan rules in Settings → Billing → Stripe → Plan rules.
- Refunds: Stripe
charge.refundedevents automatically freeze the matching license. You decide whether to revoke or keep frozen for re-activation. - Subscription deletion:
customer.subscription.deletedevents expire the license at the period end.
Hand-rolled webhook (recommended for now)
The hosted Stripe → KeyStack webhook described above is on our roadmap. For today the cleanest pattern is:
- Add an endpoint on your own backend that receives Stripe's
checkout.session.completed. - Verify Stripe's signature.
- Look up the corresponding KeyStack plan code from the
price.id. - Call
POST /v1/issueon KeyStack with the customer's email + plan code. - Email the customer the returned license key.
Less infra to share, no secret-of-a-secret, and you can run any custom logic before issuing (e.g. fraud checks, gift codes, bundling).