Charcoles Payments
Providers
Configure your payment provider credentials for Stripe or LemonSqueezy.
Stripe Configuration
Get Your Credentials
- Go to dashboard.stripe.com/apikeys
- You'll see two sets of keys: Test (prefixed
sk_test_) and Live (prefixedsk_live_) - Start with test keys while developing
- Copy your secret key and webhook secret
Find Your Webhook Secret
- Go to dashboard.stripe.com/webhooks
- Create a new endpoint or click your existing one
- Your webhook endpoint should be:
https://your-domain.com/payments/webhook - Copy the Signing secret (starts with
whsec_)
Environment Variables
Add these to your .env:
PAYMENT_PROVIDER=stripe
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PUBLISHABLE_KEY=pk_test_...
How Stripe Payment Flow Works
- Frontend calls
POST /payments/create-intentwith amount and currency - Server responds with
clientSecret - Frontend uses
clientSecretwithStripe.jsto confirm payment - User completes payment form on Stripe's hosted page
- Stripe fires
payment_intent.succeededwebhook to your server - Your server receives webhook and fulfills the order
The STRIPE_PUBLISHABLE_KEY is safe to expose in frontend code. It's never used server-side. Include it in .env for reference, but the server only reads the secret key.
LemonSqueezy Configuration
Get Your Credentials
- API Key: Go to app.lemonsqueezy.com/settings/api and generate an API key
- Store ID: Find your store ID in the URL. Go to app.lemonsqueezy.com/stores — it's the numeric ID in the URL
- Example:
app.lemonsqueezy.com/stores/12345→ Store ID is12345
- Example:
- Webhook Secret: Create a webhook in your store settings and copy the signing secret
Environment Variables
Add these to your .env:
PAYMENT_PROVIDER=lemonsqueezy
LEMONSQUEEZY_API_KEY=your_api_key
LEMONSQUEEZY_WEBHOOK_SECRET=your_webhook_secret
LEMONSQUEEZY_STORE_ID=12345
The Variant ID Requirement
LemonSqueezy uses product variants, not raw amounts. You cannot charge an arbitrary amount like The
$29.99 — you must have a product in your LemonSqueezy store first.For variable-amount payments (custom invoices, tips, or metered billing), create a "Pay What You Want" product in LemonSqueezy and use that variant's ID.When calling POST /payments/create-intent, pass variantId in the metadata:{
"amount": 2999,
"currency": "usd",
"metadata": {
"variantId": "78901"
}
}
variantId is required for LemonSqueezy. Stripe ignores it.How LemonSqueezy Payment Flow Works
- Frontend calls
POST /payments/create-intentwith variantId in metadata - Server responds with
checkoutUrl - Frontend redirects user to
checkoutUrl - User pays on LemonSqueezy's hosted checkout page
- LemonSqueezy fires
order_createdwebhook to your server - Your server receives webhook and fulfills the order
LemonSqueezy is a merchant of record — you don't see raw payment method data. LemonSqueezy handles the transaction and deposits funds to your account.
Switching Providers
Changing providers is simple — no code changes needed.
- Update
PAYMENT_PROVIDERin.envtostripeorlemonsqueezy - Add the required env vars for your new provider
- Restart your server
The adapter is instantiated once on startup based on the PAYMENT_PROVIDER value. That's it.
Test vs Live Keys
Development (Test Keys)
Use test keys while building:
- Stripe test key (starts with
sk_test_) - LemonSqueezy test mode (check the API key source)
Test keys never charge real payment methods. They're safe to keep in version control during development (though you should still use .env).
Production (Live Keys)
When you go live:
- Switch to live keys (
sk_live_for Stripe) - Update webhooks to your production URL
- Double-check
PAYMENT_PROVIDERis set correctly - Verify webhook secrets are production secrets, not test secrets
What Comes Next
- API Endpoints — Make payment requests
- Environment Variables — Complete reference
- Webhooks — Handle payment events