A checkout button is only the visible start of a payment system. A reliable digital product flow must choose the right variant, verify the provider's message, record the order once, and handle refunds and subscription changes. This guide explains a Lemon Squeezy checkout in plain language. It also shows why a product with no deliverable or release date should remain a concept instead of opening payment.
What should happen before a checkout opens?
Checkout should open only when the product and seller are ready to make the exact offer shown to the buyer. A product needs a defined file, version, documentation, price, license, and delivery method. A preorder also needs a delivery date and clear refund terms. A concept with none of these should not charge anyone.
Check the seller side as well. The public seller identity and support contact should be real, and the terms should match the product. If a payment provider requires account verification, finish that work before enabling the live switch. A server environment flag can keep the checkout closed while the site and test flow are prepared.
Use product states such as planned, preorder, and available. A planned item is visible for discovery but has no checkout. A preorder states what will be delivered and when. An available item has files and documentation ready. The server must validate the state on every checkout request, because a hidden button in the browser is not a security rule. A Lemon Squeezy checkout must never be generated for a planned item.
Write one source of truth for product status, price, and variant mapping. When the catalog, product page, and checkout use different lists, they can disagree. That can show one license price while charging another. A single product record reduces this risk.
How are products and variants related?
A Lemon Squeezy checkout is created for a specific store and variant. The checkout API describes the relationship. Your site should map its own product and license choices to provider variant IDs on the server.
For example, one product might have Single Site, Pro, and Agency licenses. Each needs a variant that represents the actual price and terms in Lemon Squeezy. Do not trust a variant ID submitted by the browser. A visitor could change it to a cheaper or unrelated option. Accept a product slug and license key, look up the allowed variant in server code, and reject an unknown pair.
The provider can show other variants of the same product unless checkout options limit them. If your site promises a specific tier, consider enabling only the intended variant in that checkout. Verify this behavior in test mode. The payment page should repeat the same license name and price the buyer saw on your site. Review each Lemon Squeezy checkout preview before release.
Keep provider IDs out of marketing copy. The customer needs the product, license limit, total charge, renewal rules, and delivery details. The ID is an internal mapping. Store it where it can be reviewed and changed without editing several pages.
If variants represent project limits, the agency license guide explains the rights each tier needs to describe.
What should the checkout API validate?
The checkout API should validate product status, license choice, seller readiness, and provider configuration before creating a payment link. Reject missing or malformed input with a clear response. The browser should never choose the amount or claim that a planned product is available.
A good flow accepts a short product identifier and a license identifier. It loads the product record, confirms that the product is available, finds the mapped variant, and checks that live payments are enabled. A separate test environment can use test variants and test credentials. Do not let a test switch silently become a live one. Create the Lemon Squeezy checkout on the server.
The Lemon Squeezy API allows a custom checkout URL and a redirect URL after purchase. Use a safe fixed return address, not an arbitrary URL from the visitor. Check that the returned checkout URL uses HTTPS and belongs to the expected provider before redirecting the buyer.
Handle provider errors without exposing the API key. A temporary failure should show a retryable checkout message, not a false “order complete” screen. Keep enough server logs to investigate, while avoiding card data and unnecessary personal information.
Why is the return page not proof of payment?
A return page proves only that a browser reached that page. A person can open it directly, bookmark it, or be redirected there while a payment is still being processed. Never grant a download or mark an order paid solely because the visitor saw “thank you.”
The payment provider sends an event to a server webhook. Your server verifies that event, records its identity, and updates the order. Only after that verified state should the fulfillment system grant access. This separation protects the seller and the buyer from confusing partial or failed payments with completed orders.
The return page can still help. It can tell the buyer that confirmation is processing and direct them to the provider receipt or support contact. Do not display a download link unless your own verified order store says the buyer is entitled to it. A successful Lemon Squeezy checkout redirect does not replace that order check.
A test should include a direct visit to the return URL without paying. The system should not create an order. This simple test catches a serious class of fulfillment mistakes.
How should a webhook signature be checked?
Verify the signature against the exact raw request body before trusting the event. Lemon Squeezy signs webhook requests with a secret. If your code parses and reformats JSON before calculating the signature, the bytes may change and the check may fail. Read the raw body, calculate the expected HMAC, and compare safely.
Keep the webhook secret on the server. Never put it in a public environment variable or browser bundle. If the secret is absent, return a configuration error rather than accepting the message. Reject a missing or invalid signature before writing an order.
Read the provider's current webhook documentation when implementing. Header names and event formats are API details that can change. The signature check is only the first step. Validate the event name, object ID, and expected shape too. Unknown events should not be treated as successful purchases.
Do not log the full payload by default. It may contain buyer information. Record a safe event ID, event type, provider object ID, and processing result. Keep sensitive details only when your fulfillment and legal duties require them.
What makes webhook handling idempotent?
Idempotent handling means the same event can arrive twice without creating two orders or sending two deliveries. Payment providers retry notifications when a server is slow or unavailable. Your code must assume duplicates are normal.
Give each event a stable identity. If the provider supplies an event ID, use it. Otherwise derive one from the signed event content and type. Save that identity in a table with a unique constraint. Insert the event and update the purchase in one database transaction so a partial failure does not mark the event complete without updating the order.
Return success for an already processed event. Do not send another license email or increase a counter. If processing fails before the transaction commits, let the provider retry. This makes the system more reliable during outages.
Test the same signed request twice. The first should update state. The second should report a duplicate or harmless success. Then send a different event for the same order, such as a refund, and confirm it changes the state correctly.
How do refunds and subscriptions change state?
Refund and subscription events should update the saved purchase state after signature verification. An order can move from paid to refunded. A subscription can become active, past due, cancelled, or expired. Your application must define what each state means for access.
Do not assume one event name tells the whole story. Inspect the provider object and its status. A cancellation may leave access active until the end of a paid period, while an expiration ends it. The exact behavior depends on the provider and product terms. Test real provider events in test mode and write down the state transitions.
A buyer should be able to ask for help with an order reference. Support staff need enough information to find the provider record without collecting card numbers. If Lemon Squeezy is the merchant of record for the transaction, direct refund handling through the relevant provider process and terms.
For preorders, Lemon Squeezy's buyer terms allow a refund request for any reason up to delivery. That is another reason a preorder must have a clear delivery record and status.
Our draft refund policy shows the customer-facing terms that must match the final checkout configuration before sales open.
What data should pass through checkout?
Pass only the minimum data needed to connect a provider event to your own product and license. The custom data guide explains that custom values sent with checkout return in webhook metadata. A product reference and license key can help map the event to the intended offer.
Do not place sensitive secrets in custom data. The values are part of the payment flow and should be treated as visible to systems beyond your app. An affiliate reference can be included when it is validated and relevant, but it should not authorize a payout by itself. Link commission credit to a verified paid order and reverse it if the order is refunded.
Store only what you need. A local purchase record might keep provider ID, product reference, license key, state, and update time. Card details belong with the provider. Define retention and privacy terms before live sales.
A local development database can use an embedded PostgreSQL compatible engine. The same schema can later run on standard PostgreSQL. Test the move before relying on it in production, especially transactions and uniqueness constraints.
How do you test the flow safely?
Use the provider's test mode and cover both success and failure paths. A successful checkout is only one case. An invalid signature, duplicate webhook, refund, cancelled subscription, and unavailable product are equally important.
Make a small scenario table. For each case, state the incoming request, expected response, database change, and buyer-visible result. Run checkout mapping for every product-license pair that will be sold. Confirm the price and license shown by the provider match the site. Repeat the test when Lemon Squeezy checkout variants change.
Test consent separately. Optional GA4 analytics should not load when a visitor rejects it. A purchase record should still work because payment verification is an essential transaction process, not an analytics event. Count a purchase in analytics only after a verified provider event if consent rules allow it.
Keep the live switch off until seller identity, product files, legal text, and provider account are complete. A tested code path is not a complete business launch. The final buyer promise must be deliverable.
How should an affiliate reference be protected?
An affiliate reference should identify a campaign, not grant trust or payment by itself. A visitor may arrive through a referral link, and the site can save a short code in a cookie. The code should come from a known partner list and should have a clear lifetime. Do not accept any text as a valid partner or let a referral URL redirect to an arbitrary outside site.
Pass the validated reference through checkout custom data. When a signed order event arrives, store it with the order. Credit a commission only when the purchase is confirmed and its eligibility rules are met. If the order is refunded, reverse or hold the credit according to the written affiliate terms. This prevents a click or an abandoned checkout from being counted as revenue.
Keep affiliate data separate from buyer identity when possible. Partners generally need a report of eligible orders and amounts, not full customer contact details. Publish the attribution window, commission rate, payout timing, and refund treatment before recruiting partners. A reliable technical path does not replace a clear partner agreement.
Frequently asked questions
Can a checkout redirect confirm an order?
No. A signed provider webhook and a saved order state are required before fulfillment.
Why save webhook event IDs?
To process retries only once. A unique event record prevents duplicate delivery and state changes.
Can I charge for a product concept with no release date?
Do not open checkout for an undefined concept. A preorder needs a clear deliverable, target date, and applicable refund terms.
Should affiliate credit be granted at click time?
No. Link it to a verified paid order and adjust it when a refund occurs.