Checkout UI is the easy half of billing. The hard half is trusting a webhook enough to unlock a download, a seat, or a feature flag. Kits that skip this half create “I paid” support loops on day one.
The minimum trustworthy flow
- Client starts Checkout with product and user metadata.
- Provider sends a signed webhook on success.
- Your handler verifies the signature with the webhook secret.
- You upsert a purchase or entitlement keyed by provider event id or session id.
- Product code checks that record before serving protected assets.
Idempotency in plain language
Providers retry webhooks. Your handler will see the same logical payment more than once. Store a unique provider event or session identifier and treat duplicates as no-ops that still return success. Double inserts are how customers get two licenses or none.
What to look for in a billing kit
- A dedicated webhook route with signature verification.
- A purchases table (or equivalent) with status and amounts in cents.
- Metadata that ties payment → user → product without guesswork.
- Test-mode instructions that do not require production keys.
Common failure modes
- Verifying nothing and trusting JSON bodies.
- Granting access in the success page loader only.
- Using price ids in code without documenting how to rotate them.
- Ignoring failed payments and chargeback hooks entirely.
Entitlements beyond a boolean
Many kits store purchased = true. That is enough for a single SKU. If you sell tiers, seats, or downloadable versions, model what was bought: product id, version channel, quantity, and whether updates are included. Your future pricing page will thank you.
How Twenty buyers experience this
On Twenty, purchase confirmation writes access you can re-download from your library. That same pattern - webhook confirmed entitlement - is what good billing kits should give your own customers.
Filter the marketplace for billing systems, then open the webhook file before you fall for the pricing table UI.