Payments

Lemon Squeezy payments for GoCommerce

A Go package that creates a Lemon Squeezy checkout at the order’s price and marks the GoCommerce order paid when a signed order_created webhook says it was paid. It needs one placeholder product in Lemon Squeezy — the one setup step Paddle does not.

What it does

The module registers “lemonsqueezy” as a payment method. At checkout it creates a Lemon Squeezy checkout against a store and a variant you name, replaces the variant’s price with the order’s total in minor units, and answers with a redirect intent carrying the checkout URL.

Lemon Squeezy then calls POST /api/checkout/lemonsqueezy/webhook. The module verifies X-Signature and, when order_created arrives with the status paid, asks the engine to mark the order paid, recording Lemon Squeezy’s own order id — the one a refund is later issued against.

Why the placeholder: Lemon Squeezy sells items from its own catalogue, so a checkout must name a variant that already exists there. You create one product — any name, any price, never shown to a shopper — and every order becomes that variant at the order’s own price. Like Paddle, Lemon Squeezy is the merchant of record and works out the tax itself.

Configuration

Four settings are required: the API key, the webhook’s signing secret, and the store and placeholder variant every checkout is created against. Set them in Config from your own main(), or under Settings › Payment methods.

Lemon Squeezy module settings — 6 settings, 4 required
SettingEnvironment variableRequiredWhat it does
APIKey
API key
LEMONSQUEEZY_API_KEY Yes Sent as a bearer token. Not sent to the storefront.
WebhookSecret
Webhook signing secret
LEMONSQUEEZY_WEBHOOK_SECRET Yes Verifies the X-Signature header. Required because, as the code puts it, without it any caller could mark orders paid.
StoreID
Store ID
LEMONSQUEEZY_STORE_ID Yes The Lemon Squeezy store every checkout is created in.
VariantID
Placeholder variant ID
LEMONSQUEEZY_VARIANT_ID Yes The catalogue item every checkout is created against; its price is replaced by the order total.
BaseURL
API base URL
— No Overrides https://api.lemonsqueezy.com, for tests. Empty for production.
Client — No Replaces the HTTP client, which otherwise times out after 20 seconds. Go only; not in the panel.

The module reads its Config struct, not the environment. The variable names are the ones the package’s own example or the reference binary uses; in your own main() you choose where each value comes from. Where a setting has a panel label, the admin’s settings drawer can hold it too, and a value typed there wins over Config.

Setting it up

  1. Create the placeholderIn Lemon Squeezy, create one product with any name and price, and note the store id and its variant id. Shoppers never see it.
  2. Add the webhookPoint a webhook at https://your-api-host/api/checkout/lemonsqueezy/webhook for order_created, and keep its signing secret.
  3. Install and configurePass lemonsqueezy.New to gocommerce.New as below, or run the reference binary with -gateways and fill in Settings › Payment methods. Leave GoCommerce’s tax rates empty.
  4. Take a paymentPOST /api/checkout/lemonsqueezy answers with a redirect intent whose url is the hosted checkout. A paid order_created marks the order paid.

main.go

import (
	"os"

	"github.com/itswadesh/gocommerce/core"
	lemonsqueezy "github.com/itswadesh/gocommerce/ext/payments-lemonsqueezy"
)

app, err := gocommerce.New(cfg,
	lemonsqueezy.New(lemonsqueezy.Config{
		APIKey:        os.Getenv("LEMONSQUEEZY_API_KEY"),
		WebhookSecret: os.Getenv("LEMONSQUEEZY_WEBHOOK_SECRET"),
		StoreID:       os.Getenv("LEMONSQUEEZY_STORE_ID"),
		VariantID:     os.Getenv("LEMONSQUEEZY_VARIANT_ID"),
	}),
)

The package doc’s own example, with its imports; cfg is your gocommerce.Config. With an empty lemonsqueezy.Config the module installs idle and waits for the panel. Import path github.com/itswadesh/gocommerce/ext/payments-lemonsqueezy.

How it works

What it does not do

Read these before an order depends on it. No store is known to run GoCommerce in production yet, so these come from the code, not from anyone’s experience.

FAQ

Questions about the Lemon Squeezy module

Why does it need a placeholder product?

Lemon Squeezy sells items from its own catalogue, so a checkout must name a store and a variant that already exist there. The module overrides that variant’s price with the order total, so one placeholder serves every order. The package states it up front because the alternative is discovering it from an error at the first real checkout.

Should I keep GoCommerce’s tax rates?

No. Lemon Squeezy is the merchant of record and works out the tax on the sale itself. Leave GoCommerce’s rates empty so the total it sends is what the shopper pays.

What is the webhook URL?

POST /api/checkout/lemonsqueezy/webhook on the host that serves your GoCommerce API. order_created settles a paid order; order_refunded is logged; anything else is acknowledged.

Is this a Lemon Squeezy partnership?

No. The module calls Lemon Squeezy’s public API with keys you supply. Lemon Squeezy does not endorse GoCommerce, and no store is known to run this module in production yet.

Source

Everything on this page is read from ext/payments-lemonsqueezy in the GoCommerce repository, MIT licensed. When this page and the code disagree, the code is right and this page is out of date.Lemon Squeezy is a trademark of its owner; this module talks to its public API and implies no endorsement. See trademarks.

Try it against a store of your own

The one-command stack gives you GoCommerce’s API and admin on your own machine in minutes. Add this module to it and try it on test orders before a real one depends on it.

Chat on WhatsApp