Purchase Automation Guide
This guide shows you how to automatically grant audiobook access when customers payβno manual work required!
π― How It Works
Customer Pays β Webhook Fires β User Created β Access Granted β Email Sent
β β β β β
Stripe Your Worker Find/Create Purchase Welcome to
Gumroad Receives Account Recorded Library!
LemonSqueezy Webhook
β Supported Payment Providers
| Provider | Best For | Fee |
|---|---|---|
| Stripe | Full control, subscriptions | 2.9% + $0.30 |
| LemonSqueezy | Simple, EU VAT handled | 5% + $0.50 |
| Gumroad | Audience already there | 10% |
π§ Option 1: Stripe (Recommended)
Step 1: Create Products in Stripe
Stripe Dashboard β Products β Add Product
Product 1:
Name: "WILDFLOWER Audiobook"
Price: $14.99
Metadata: book=wildflower
Product 2:
Name: "TALLY Audiobook"
Price: $14.99
Metadata: book=tally
Product 3 (Bundle):
Name: "The Inverter Cycle - Complete"
Price: $24.99
Metadata: book=wildflower,tally
Step 2: Set Up Webhook
Stripe Dashboard β Developers β Webhooks β Add Endpoint
Endpoint URL: https://audio.kbird.ai/webhooks/stripe
Select Events:
βοΈ checkout.session.completed
βοΈ payment_intent.succeeded
Signing Secret: (copy this, you'll need it for verification)
Step 3: Test Purchase
# Use Stripe CLI to test
curl -X POST https://audio.kbird.ai/webhooks/stripe \
-H "Content-Type: application/json" \
-d '{
"type": "checkout.session.completed",
"data": {
"object": {
"id": "test_session_123",
"customer_email": "[email protected]",
"amount_total": 1499,
"metadata": { "book": "wildflower" }
}
}
}'Step 4: Add Stripe Secret (Optional Verification)
# Add webhook signing secret for verification
npx wrangler secret put STRIPE_WEBHOOK_SECRET
# Paste your Stripe webhook signing secretπ Option 2: LemonSqueezy
Step 1: Create Products
LemonSqueezy Dashboard β Products β Create Product
Product:
Name: WILDFLOWER Audiobook
Price: $14.99
File: (optional - just a README with link to audio.kbird.ai)
Step 2: Configure Webhook
Settings β Webhooks β Add Webhook
Webhook URL: https://audio.kbird.ai/webhooks/lemonsqueezy
Events:
βοΈ order_created
Signing Secret: (copy from webhook details)
Step 3: Add Secret
npx wrangler secret put LEMONSQUEEZY_WEBHOOK_SECRETπ¦ Option 3: Gumroad
Step 1: Create Products
Gumroad β Products β Add Product
Product:
Name: WILDFLOWER Audiobook
Price: $14.99
File: (optional, or just description with instructions)
Step 2: Enable Webhook
Settings β Advanced β Webhooks
Payload URL: https://audio.kbird.ai/webhooks/gumroad
Secret: (generate random string, save it)
Step 3: Add Secret
npx wrangler secret put GUMROAD_WEBHOOK_SECRETπ§ Customer Email Flow
After purchase, customers should receive:
Immediate (Payment Confirmation)
From: Payment provider (Stripe/Gumroad/etc) Subject: βYour receipt for WILDFLOWER Audiobookβ
Follow-up (Access Instructions) - YOU SEND THIS
From: [email protected] Subject: βYour WILDFLOWER Audiobook is ready!β
Hi [Name],
Thank you for purchasing WILDFLOWER!
π§ Access Your Audiobook:
https://audio.kbird.ai
π§ Your Login Email: [[email protected]]
π Set Your Password:
https://audio.kbird.ai/auth/forgot-password
What to expect:
β’ Chapter 18 is FREE (no login needed)
β’ Chapters 1-17 are in your library
β’ Stream anytime, forever
β’ Works on all devices
Questions? Reply to this email.
β Kristopher Richards
π§ͺ Testing Webhooks Locally
Using Stripe CLI
# Install Stripe CLI
brew install stripe/stripe-cli/stripe
# Login
stripe login
# Forward webhooks to local dev
stripe listen --forward-to localhost:8787/webhooks/stripe
# Trigger test event
stripe trigger checkout.session.completedUsing ngrok
# If webhooks need public URL
npx ngrok http 8787
# Use the ngrok URL in Stripe webhook settings:
# https://abc123.ngrok.io/webhooks/stripeπ Security Checklist
- Webhook endpoints verify signatures
- HTTPS only (Cloudflare handles this)
- Duplicate event handling (idempotent)
- Customer email validation
- Rate limiting on endpoints (Cloudflare WAF)
π Troubleshooting
Webhook not firing?
# Check Cloudflare logs
npx wrangler tail
# Check if endpoint is reachable
curl -X POST https://audio.kbird.ai/webhooks/stripe \
-H "Content-Type: application/json" \
-d '{"type":"test"}'Customer didnβt get access?
- Check
purchasestable in D1:
SELECT * FROM purchases
WHERE payment_id = 'pi_xxx'
ORDER BY purchased_at DESC;- Check
userstable:
SELECT * FROM users
WHERE email = '[email protected]';- Check worker logs in Cloudflare dashboard
Duplicate purchases?
The webhook handler is idempotentβsame payment_id wonβt create duplicate purchases because of unique constraints. But you should still handle this:
// Check if purchase already exists
const existing = await env.DB.prepare(
'SELECT id FROM purchases WHERE payment_id = ?'
).bind(session.id).first();
if (existing) {
return jsonResponse({ success: true, message: 'Already processed' });
}π‘ Advanced: Custom Payment Flow
Example: Buy Button on Your Site
<!-- On kbird.ai -->
<button id="buy-wildflower">Buy WILDFLOWER - $14.99</button>
<script>
document.getElementById('buy-wildflower').addEventListener('click', async () => {
// Create Stripe Checkout Session
const response = await fetch('https://api.kbird.ai/create-checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
book: 'wildflower',
success_url: 'https://kbird.ai/thanks',
cancel_url: 'https://kbird.ai/cancel'
})
});
const { url } = await response.json();
window.location = url;
});
</script>Backend (Optional)
If you want a custom checkout server:
// api.kbird.ai/create-checkout
app.post('/create-checkout', async (req, res) => {
const session = await stripe.checkout.sessions.create({
line_items: [{
price_data: {
currency: 'usd',
product_data: { name: 'WILDFLOWER Audiobook' },
unit_amount: 1499,
},
quantity: 1,
}],
mode: 'payment',
success_url: req.body.success_url,
cancel_url: req.body.cancel_url,
metadata: { book: req.body.book }
});
res.json({ url: session.url });
});π Monitoring
Set up alerts for:
- Failed webhooks (check Cloudflare Workers analytics)
- Unusually high refund rates
- Customers without purchases trying to access (could indicate sharing)
-- Find users with high download counts
SELECT user_id, COUNT(*) as downloads
FROM downloads
WHERE access_type = 'purchase'
GROUP BY user_id
HAVING downloads > 100;π Youβre Done!
Once configured:
- Customer clicks βBuyβ on your site or payment provider
- Pays with credit card/PayPal
- Webhook automatically fires
- Account created (if new) or existing found
- Purchase recorded in database
- Customer receives email
- They log in at audio.kbird.ai and listen!
No manual work required! π§
Need Help?
- Stripe docs: https://stripe.com/docs/webhooks
- LemonSqueezy docs: https://docs.lemonsqueezy.com/guides/developer-guide/webhooks
- Gumroad docs: https://gumroad.com/api#webhooks