Engineering

Stripe + License Keys: Automatic Provisioning with Webhooks

TOT
Traffic Orchestrator Team
Engineering
April 8, 2026 4 min read 463 words
Share

<h2>Automate License Keys with Stripe Webhooks</h2>

<p>When a customer pays, they should receive a license key instantly. No manual steps, no support tickets, no delays. This tutorial shows you how to connect Stripe webhooks to Traffic Orchestrator for fully automated license provisioning.</p>

<h3>The Flow</h3>

<ol> <li>Customer clicks "Buy" on your pricing page</li> <li>Stripe Checkout handles the payment</li> <li>Stripe fires a <code>checkout.session.completed</code> webhook</li> <li>Your webhook handler calls Traffic Orchestrator to create a license</li> <li>The license key is emailed to the customer automatically</li> </ol>

<h3>Step 1: Set Up the Stripe Webhook Endpoint</h3>

<pre><code>import Stripe from 'stripe' import { TrafficOrchestrator } from '@traffic-orchestrator/client'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY) const toClient = new TrafficOrchestrator({ baseUrl: 'https://api.trafficorchestrator.com/api/v1', apiKey: process.env.TO_API_KEY })

app.post('/webhooks/stripe', async (req, res) => { const sig = req.headers['stripe-signature'] let event

try { event = stripe.webhooks.constructEvent( req.body, sig, process.env.STRIPE_WEBHOOK_SECRET ) } catch (err) { return res.status(400).send('Webhook signature verification failed') }

switch (event.type) { case 'checkout.session.completed': await handleCheckoutCompleted(event.data.object) break case 'customer.subscription.deleted': await handleSubscriptionCanceled(event.data.object) break case 'charge.refunded': await handleRefund(event.data.object) break }

res.json({ received: true }) })</code></pre>

<h3>Step 2: Handle Checkout Completion</h3>

<pre><code>const planConfig = { starter: { maxDomains: 5, features: ['basic'], validations: 1000 }, professional: { maxDomains: 25, features: ['basic', 'analytics', 'webhooks'], validations: 10000 }, business: { maxDomains: 100, features: ['basic', 'analytics', 'webhooks', 'sso', 'priority_support'], validations: 100000 } }

async function handleCheckoutCompleted(session) { const email = session.customer_email const planId = session.metadata.plan_id || 'starter' const config = planConfig[planId]

// Create the license via Traffic Orchestrator API const license = await toClient.createLicense({ email, planId, maxDomains: config.maxDomains, features: config.features, monthlyLimit: config.validations })

// Send the license key to the customer await sendEmail({ to: email, subject: 'Your License Key is Ready', template: 'license-delivery', data: { licenseKey: license.key, planName: planId, docsUrl: 'https://trafficorchestrator.com/docs/quickstart/node' } })

console.log('License provisioned:', license.key, 'for', email) }</code></pre>

<h3>Step 3: Handle Cancellations and Refunds</h3>

<pre><code>async function handleSubscriptionCanceled(subscription) { const customerId = subscription.customer const customer = await stripe.customers.retrieve(customerId)

// Revoke the license await toClient.revokeLicense({ email: customer.email, reason: 'subscription_canceled' }) }

async function handleRefund(charge) { // Full refund — revoke license if (charge.amount_refunded === charge.amount) { await toClient.revokeLicense({ stripeChargeId: charge.id, reason: 'full_refund' }) } // Partial refund — downgrade instead else { await toClient.downgradeLicense({ stripeChargeId: charge.id, newPlan: 'starter' }) } }</code></pre>

<h3>Step 4: Test the Integration</h3>

<pre><code># Use Stripe CLI to test locally stripe listen --forward-to localhost:3000/webhooks/stripe

Trigger a test checkout event stripe trigger checkout.session.completed</code></pre>

<h3>Production Checklist</h3>

<ul> <li>✅ Verify Stripe webhook signatures in production</li> <li>✅ Handle duplicate events (idempotency)</li> <li>✅ Log all provisioning for audit trail</li> <li>✅ Set up alerts for failed provisioning</li> <li>✅ Test the full flow: purchase → webhook → license → email</li> </ul>

<p>For more payment integrations, see our guides on <a href="/blog/automating-license-provisioning-with-lemonsqueezy-webhooks">LemonSqueezy</a> and <a href="/blog/automating-license-provisioning-with-paddle-webhooks">Paddle</a> webhook integration.</p>

Related Articles

TOT
Traffic Orchestrator Team
Engineering

The engineering team behind Traffic Orchestrator, building enterprise-grade software licensing infrastructure used by developers worldwide.

Was this article helpful?
Get licensing insights delivered

Engineering deep-dives, security advisories, and product updates. Unsubscribe anytime.

Share this article
Free Plan Available

Ship licensing in your next release

5 licenses, 500 validations/month, full API access. Set up in under 5 minutes — no credit card required.

2-minute setup No credit card Cancel anytime