Lemon Squeezy and CodeWords: merchant of record changes the work
Tax handled for you, payouts that do not match orders, webhooks as the source of truth, and the licence keys and entitlements that actually gate your product.
On this page
- What we'll cover
- What merchant of record actually means
- What Lemon Squeezy reaches
- Webhooks as the source of truth
- Connecting it to CodeWords
- Seven automations worth building
- Entitlements, which are the real integration
- Checkout, and what you carry through it
- Building it so it survives
- Limits worth knowing about
- What to build first
- Frequently asked questions
- Related reading
Lemon Squeezy is a merchant of record, and that single fact changes what you have to build. It sells to your customer, which means it handles sales tax and VAT registration, calculation, and remittance across jurisdictions — the part of selling software internationally that is disproportionately painful relative to its glamour.
What it also means is that your payouts will not match your orders, your customer's invoice comes from a company that is not yours, and your revenue reporting needs to account for both. Automation around it is shaped accordingly.
What we'll cover
- What merchant of record actually means
- What Lemon Squeezy reaches
- Webhooks as the source of truth
- Connecting it to CodeWords
- Seven automations worth building
- Entitlements, which are the real integration
- Checkout, and what you carry through it
- Building it so it survives
- Limits worth knowing about
- What to build first
- Frequently asked questions
What merchant of record actually means
Tax is handled. Registration, calculation, collection, and remittance across jurisdictions, which for a small team selling internationally is the difference between shipping and spending a quarter on compliance.
The customer's receipt shows Lemon Squeezy, not your company. Some buyers query this, and it is worth a line in your own confirmation email.
Payouts are net and on a schedule, so the money arriving in your bank does not correspond to a set of orders one to one. Reconciliation is against the payout report, not against your order list.
Refunds and chargebacks are handled on your behalf, with the amounts appearing in the payout.
Fees include the service being provided, so comparing the headline rate against a payment processor alone is comparing different things.
For automation: your own revenue reporting should be built from order data, and your bank reconciliation from payout data, and the two will never line up directly. Building both from the start avoids a confusing month later.
What Lemon Squeezy reaches
Orders and order items can be listed and read, with their tax and discount detail.
Subscriptions can be read, paused, resumed, cancelled, and changed, which covers most lifecycle automation.
Customers can be listed and updated, and they are the join between billing and your own user records.
Products and variants define what you sell, with pricing.
Licence keys can be created, activated, validated, and deactivated, which is the built-in mechanism for gating software.
Discounts can be created and managed programmatically, which suits campaign automation.
Checkouts can be created with pre-filled data and custom fields, which is how you carry your own identifiers through a purchase.
Webhooks fire on the events that matter, and they are the mechanism to build on.
Webhooks as the source of truth
Polling the API for changes is the approach people default to, and it is the wrong one here.
Subscription state changes arrive as events, including the renewals and payment failures that polling would only notice later.
Verify the signature on every webhook. The endpoint is public and will receive requests you did not cause.
Respond quickly and process afterwards. A slow endpoint causes retries, which causes duplicate processing if you have not made it idempotent.
Handle at-least-once delivery. Store the event identifier and ignore repeats.
Expect out-of-order arrival. A cancellation can arrive before the update that preceded it, so reconcile against the current state rather than applying events blindly.
Reconcile periodically anyway. A scheduled comparison between your entitlements and Lemon Squeezy's subscriptions catches whatever the webhooks missed, and something always eventually slips.
Connecting it to CodeWords
CodeWords connects to more than 3,000 integrations, and the connection is made once and reused.
- Open CodeWords and start a new automation.
- Describe what should happen in plain language to Cody, the automation builder: which event, and what should change in your own systems.
- Authorize the connection with an API key for the store.
- Describe the exceptions: a payment failure, a subscription for a customer you cannot match, a refund after access was granted.
- Use test mode end to end before anything runs against real purchases.
You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.
Seven automations worth building
Provisioning on purchase. Create the account, grant access, and send the welcome message within seconds of payment. The one that has to work.
Entitlement changes on subscription events. Upgrades, downgrades, cancellations, and renewals reflected in what the customer can actually do.
Dunning support. When a payment fails, tell the customer in your own voice, with a direct link to fix it, rather than relying solely on the platform's emails.
Reconciliation between billing and access. Compare active subscriptions against granted access, both directions, and report mismatches. Both directions matter: people with access who are not paying, and people paying who cannot get in.
Revenue reporting from orders, with tax separated and refunds accounted for, delivered rather than exported.
Payout reconciliation. Match payouts to your accounting records, which is where the merchant of record model makes manual work otherwise.
Cancellation signal capture. Record cancellations with any stated reason and surface them where product decisions are made, rather than leaving them in a billing dashboard.
Entitlements, which are the real integration
The question that matters is not what the customer bought. It is what they can currently do.
Keep entitlements in your own system, derived from billing rather than read from it live. Your product should not call the billing API on every request.
Derive from the subscription state, and define what each state means before you build — particularly past due, which is the one people forget.
Define grace behaviour explicitly. A failed payment should not lock somebody out instantly, and it should not grant indefinite free access either. Pick the window and write it down.
Handle refunds. Access granted on purchase needs revoking on refund, and this is a common gap.
Licence keys suit desktop and downloadable software, where the product cannot check a subscription on every launch. For a hosted product, entitlements in your own database are simpler and more flexible.
Log every change with its cause. When a customer says they lost access unexpectedly, you want the event that caused it, and reconstructing it afterwards is not possible without the log.
Checkout, and what you carry through it
The checkout is the seam between your product and the billing platform, and what you put into it determines how much matching you have to do afterwards.
Create the checkout from your own system rather than linking to a generic one, so you control what goes into it.
Pass your user identifier as custom data. It comes back on the order and on every subsequent subscription event, which turns matching into a lookup.
Pre-fill what you already know. Email and name reduce friction and remove a class of mismatch caused by somebody typing a different address.
Record the intent before redirecting. A row saying this user started a purchase at this time makes an abandoned checkout visible and a failed provision diagnosable.
Do not trust the return URL. The customer returning to your success page is not confirmation of payment; the webhook is. Building on the redirect is how people end up granting access for payments that did not complete.
Handle the customer who never returns. Payment succeeds, the browser closes, and provisioning must still happen — which it does, if it is driven by the webhook rather than the page.
Building it so it survives
Make provisioning idempotent. Key on the order or subscription identifier, since a repeated webhook must not create a second account.
Carry your own identifier through checkout using custom fields, so matching a purchase to a user is a lookup rather than an email comparison.
Match on the billing customer identifier, not the email address, since people buy with one address and use another.
Reconcile on a schedule as well as handling events, because events are eventually missed.
Report the outcome. Provisioned, changed, revoked, and mismatched, with the last count being the one that matters.
Limits worth knowing about
Rate limits apply, and bulk reporting should use listings with pagination rather than fetching records one at a time.
Test mode is separate from live, with separate data and keys, so a test never touches real customers — confirm which mode a key belongs to.
Webhook retries have a limit, after which the event is lost, which is the strongest argument for periodic reconciliation.
Payout timing depends on your account, so reconciliation automation should key on the payout rather than on a date.
Some subscription changes have proration behaviour that affects the amounts, which matters for reporting and is not always obvious in the totals.
What to build first
The reconciliation between active subscriptions and granted access, run daily, reported in both directions. It writes nothing, it needs only read access, and it catches the two failures that cost most: customers paying without access, which produces support tickets and cancellations, and access without payment, which is revenue leaking quietly.
Two habits make the difference. Report both directions separately, since they have different urgencies — a paying customer locked out is urgent and free access is merely costly. And include the cause where you can, because most mismatches trace to one webhook that failed on a specific day.
Frequently asked questions
Why does the payout not match our orders?
Because Lemon Squeezy is the merchant of record: payouts are net of fees, tax, refunds, and chargebacks, on their own schedule. Reconcile revenue from order data and bank deposits from payout data, and accept that the two will not line up one to one.
Should I poll the API or use webhooks?
Webhooks, with scheduled reconciliation alongside. Subscription events — renewals, failures, cancellations — arrive promptly as webhooks, and the reconciliation catches whatever a failed delivery lost.
What should happen when a payment fails?
Tell the customer in your own voice with a direct link to fix it, and apply a defined grace period before restricting access. Instant lockout on a first failure is a poor experience; indefinite access is a revenue leak. Choose the window deliberately.
Do I need licence keys?
For desktop or downloadable software, yes — that is what they are for. For a hosted product, entitlements in your own database derived from subscription events are simpler, more flexible, and easier to reason about.
How do I match a purchase to a user?
Pass your own identifier through checkout as a custom field, and match on the billing customer identifier thereafter. Matching on email breaks as soon as somebody pays with a different address from the one they signed up with, which is common.
What happens when a webhook fails?
It is retried a limited number of times and then lost. That is why a scheduled reconciliation between billing state and your entitlements is not optional, and why it is the first thing worth building.
Does the customer see our company on the receipt?
They see Lemon Squeezy as the seller, since it is the merchant of record. Mentioning that in your own confirmation email prevents a recurring support question and the occasional unnecessary chargeback.
Should provisioning happen on the success page?
No. The customer returning to your success page is not proof of payment, and plenty of customers never return at all. Drive provisioning from the webhook, and let the success page tell them what is happening.
How do I make abandoned checkouts visible?
Record the intent before redirecting — this user started a purchase at this time — and compare against completed orders. It also makes a failed provision diagnosable, since you can see the attempt that has no matching account.