Lemon Squeezy affiliate tracking with your own portal
Lemon Squeezy at a glance
Does Lemon Squeezy have its own affiliate program?
Yes. Lemon Squeezy has a built-in affiliate program for merchants with a tracking script, an affiliate hub and payouts it runs for you. It adds a 3% fee on each referred order on top of the normal platform fee, per its fees page in November 2026.
Affiliate payouts are created on the 1st and 15th of each month and paid on the 14th and 28th. Commissions are held for 30 days and the default minimum is $10. Source: Lemon Squeezy payouts (November 2026).
Lemon Squeezy's program is the simpler choice when you sell only there and want its hub. OpenPromoter fits when you want your own partner portal and payout rails or sell through more than one billing system.
| As of November 2026 | OpenPromoter | Lemon Squeezy affiliates |
|---|---|---|
| Fee on referred orders | None. See pricing | 3% on top of the platform fee |
| Payout schedule | Weekly, monthly or manual | Created on the 1st and 15th |
| Default minimum payout | $50 | $10 |
| Default hold | 30 days | 30 days |
| Partner portal | Your own portal and domain | The Lemon Squeezy affiliate hub |
| Billing systems | Five plus the REST API | Lemon Squeezy |
How Lemon Squeezy affiliate tracking works with custom data
Lemon Squeezy checkout accepts custom data in the checkout URL as checkout[custom][key]. OpenPromoter reads op_click from meta.custom_data on each order and subscription webhook it receives. The value comes from window.openpromoter.clickId, which op.js sets on your page after a partner click.
Lemon Squeezy documents the format in its custom data guide. The same guide shows checkout_data.custom for checkouts created through the API. The tracking docs explain how op.js sets the click id.
Discount codes as partner codes
A discount code on the order counts as the partner's coupon code. A sale with that code is credited with or without a click. Create the code in Lemon Squeezy and enter it on the partner's page.
Renewals keep the partner
Lemon Squeezy includes the custom data in subscription webhooks too. After the first credited payment, the customer is linked to the partner. Each later subscription payment is credited to the same partner.
// Add the click id to every Lemon Squeezy checkout link on the page
window.addEventListener("load", () => {
const id = window.openpromoter?.clickId;
if (!id) return;
for (const a of document.querySelectorAll('a[href*="lemonsqueezy.com"]')) {
const url = new URL(a.href);
url.searchParams.set("checkout[custom][op_click]", id);
a.href = url.toString();
}
});Set up Lemon Squeezy affiliate tracking in four steps
Lemon Squeezy affiliate tracking needs one webhook and one custom data field. You add the webhook in your store settings, choose a signing secret and select eight events. Then you add the click id to your checkout links and test the flow in test mode.
- 1
Add a webhook
In Lemon Squeezy, go to Settings > Webhooks and add /api/webhooks/lemonsqueezy/<workspaceId>.
- 2
Choose a signing secret
Type a secret of 6 to 40 characters and paste it into Settings > Integrations.
- 3
Select eight events
Tick every event in the table below and save the webhook.
- 4
Pass the click id
Add checkout[custom][op_click] to each checkout link.
Lemon Squeezy signs each request with an HMAC of the raw body in the X-Signature header. OpenPromoter checks it on every request. Source: Lemon Squeezy signing docs (November 2026).
The billing providers docs list the URL and events with copy-ready values.
Lemon Squeezy webhook events and what each one does
OpenPromoter reads eight Lemon Squeezy webhook events. Two book commissions, two handle refunds and four follow the subscription status. An order books a commission only when its status is paid, and each event is processed once even when Lemon Squeezy sends it again.
| Event | What OpenPromoter does |
|---|---|
| order_created | Books the commission on a paid order |
| subscription_payment_success | Books the commission on each renewal in the window |
| order_refunded | Reduces or reverses the order commission |
| subscription_payment_refunded | Reduces or reverses the renewal commission |
| subscription_created | Tracks the subscription and its status |
| subscription_updated | Updates trial, active and past due status |
| subscription_cancelled | Stops recurring commissions |
| subscription_expired | Stops recurring commissions |
The commission base is the subtotal minus the discount total. Tax on the order is excluded.
How refunds and renewals change commissions
A refund on an order or a subscription payment reduces the commission in proportion. A full refund reverses it and a refund after payout becomes a clawback on the next payout. Cancelled and expired subscriptions stop recurring commissions for that customer.
Refunds
order_refunded and subscription_payment_refunded carry the amount refunded so far. OpenPromoter compares it with the total and adjusts the commission to match.
Set the hold period to at least your refund window. The default is 30 days.
Disputes
OpenPromoter reads no Lemon Squeezy dispute event today. Keep the hold period long enough to cover chargebacks. You can hold any commission by hand when you see one.
Trials and cancellations
A trial shows as trialing and earns nothing until a payment succeeds. subscription_cancelled and subscription_expired both stop recurring commissions.
Test in Lemon Squeezy test mode
Lemon Squeezy test mode sends webhooks for test orders like live mode does. OpenPromoter tags those orders and commissions as Test and the Delete test data button removes them before launch. Test and live webhooks are separate in Lemon Squeezy and you need one in each mode.
Give both webhooks the same signing secret. OpenPromoter stores one secret for each provider.
You can resend any event from a test order or subscription in the Lemon Squeezy admin. Source: Lemon Squeezy webhook testing (November 2026).
Common Lemon Squeezy tracking mistakes
Most Lemon Squeezy tracking problems come from custom data in the wrong shape or a webhook set up in one mode only. Running two affiliate programs on the same product is the other common cause. Each mistake below comes with its fix.
Custom data in the wrong shape
Use checkout[custom][op_click]. A plain op_click query parameter is not passed to the webhook.
A live webhook only
Test mode needs its own webhook. Without it test orders never reach OpenPromoter.
Two programs on one sale
With Lemon Squeezy affiliates also on, one sale can pay two partners. Run one program per product.
Missing refund events
Select order_refunded and subscription_payment_refunded. Otherwise refunds keep the commission.
Old ?aff= links
op.js does not read the aff parameter. Partners moving over need new links.
A short hold period
Set the hold period to at least your refund window. The default is 30 days.
Pay Lemon Squeezy affiliates and handle tax
Lemon Squeezy pays you and OpenPromoter pays your partners. Partners choose Stripe Connect, PayPal, Wise or manual payment in their portal and you approve each batch before it goes out. Each rail charges its own fee and OpenPromoter takes 0% of payouts on every plan.
Lemon Squeezy is a merchant of record and handles sales tax on your orders. Source: Lemon Squeezy merchant of record (November 2026). Partner tax forms are still yours to collect.
Partners paid by PayPal, Wise or by hand submit a W-9 or a W-8BEN in the portal. EU VAT ids are checked against the VIES service. Every payout gets a self-billed invoice with a sequential number.
US partners need a W-9 before their payouts for the year pass the 1099-NEC threshold. That threshold is $2,000 for payments made in 2026. The 1099 guide for affiliates covers the filing.
Questions
How is the click id passed to Lemon Squeezy?
Does the 3% Lemon Squeezy affiliate fee apply?
Are Lemon Squeezy test orders counted?
Do renewals earn recurring commissions?
Can I move my Lemon Squeezy affiliates over?
Do Lemon Squeezy discount codes count?
Related

[ openpromoter ]
Try it with your own Stripe account
Free on Cloud up to $1k a month in partner revenue or free forever on your own server.