Guides

Selling products and courses

Products, checkout, coupons and invoices — and the places where money quietly goes missing.

Created 22 Aug 2026

Everything needed to take money for a product — one-off, subscription, payment plan or pay-what-you-want — with a checkout, a discount code, a numbered invoice, and access granted automatically on payment.

Do the invoice settings first

Every invoice freezes your business details onto itself at issue, so your first sale carries whatever is in there at the time.

General Settings → Branding tab: Business Name and the Address fields. Bank Statement Name is optional — empty means buyers see your business name. Check the live "Buyers see:" preview under it: 22 characters is the hard cap on both gateways, accents and punctuation are stripped, an invalid descriptor fails the payment itself, and it cannot be changed after the first charge.

General Settings → General tab:

  • Tax Rate (VAT) — one rate for the whole install, default 0.
  • Price Display — leave it on Gross (incl. tax). No checkout path adds VAT on top of your listed price; the invoice works backwards from what was charged. Net makes your invoice totals disagree with what you collected.
  • Invoice details — Tax number, VAT ID, Register entry, Bank details. Nothing checks these before a sale, so an incomplete invoice goes out silently.
  • Invoice languageSite default language plus English, German and Spanish, the only complete translations. A site in any other language gets English.
  • Small business (§19 UStG) — forces the invoice rate to 0 and prints the required note instead of a tax line.

No VAT engine: one flat rate, no per-country rates, reverse charge, OSS or Stripe Tax. Cross-border EU B2C is yours to handle elsewhere.

Connect Stripe, PayPal, or both

Admin → Integrations, then the Stripe or PayPal card: an Enable switch, separate Test Keys and Live Keys, and a Test Connection button once a key is saved. Keys are stored encrypted in the database, and webhooks are registered and re-checked at every server boot — no URL to paste anywhere.

A gateway appears at checkout only when it is switched on and has the right key stored — and for Stripe that means the Live Secret Key specifically. Test keys alone are not enough: with only test keys saved, Stripe counts as unavailable at checkout even in test mode, the payment picker never offers Card, and the buy button falls back to PayPal. So paste both the test and the live Stripe secret key before you rehearse anything. PayPal is more forgiving and accepts either its live or its sandbox client ID.

With both gateways usable the buyer gets a Payment method picker: Card and PayPal. What sits behind Card is a Stripe Dashboard setting, and what Stripe renders also depends on the buyer's country, currency and amount — a method you enabled not appearing for one buyer is not a fault.

Both gateways cover all four paid modes, but not identically:

  • Payment plans. PayPal bills a plan as a subscription and collects it itself. Stripe charges only the first payment and leaves the rest as scheduled rows something external must trigger — see the last section.
  • Billing addresses. Stripe requires one; PayPal one-time orders do not, so a PayPal invoice can print with little or no buyer address.
  • Zero-value orders. PayPal refuses anything under 0.01, and rejects a coupon that zeroes a subscription.
  • Delayed methods. SEPA Direct Debit, bank transfer and some Klarna flows take hours or days. Access and the confirmation email wait for the money, and the success page does not claim success meanwhile. A buyer reporting "pending" is not a bug.
  • The German withdrawal waiver. The § 356 (5) BGB checkbox gates the buy button for everyone, but the accepted text is recorded — with IP and user agent — only on the Stripe one-time path. PayPal, subscriptions, plans and voluntary payments take the tick without keeping the evidence.

Build the product

Admin → Products → Products tab → Add Product. Six tabs.

General — Title, Type (Live Webinar, Course, Workshop, Ebook, Membership, Coaching, Template, Licence, Other), Category (required free text) and Description. All four block Create Product, as does Price once you tick a paid type — the form stops at the first one missing and tells you which. There is no slug field; the URL comes from the title and is previewed under Auto-generated URLs. Rename later and the slug changes with it: the old /products/… address gets a redirect automatically, the member-content address does not, so access links in already-sent emails break. Send an abandoned checkout email is also on this tab, under Recovery, off by default; it arms as checkout starts and cancels for anyone who buys within the hour.

Pricing — tick one or more Payment Types: Free, Voluntary, One-time, Subscription, Installments. Free is mutually exclusive; ticking it clears the paid ones. The rest combine and the buyer chooses on the sales page. Then Price and Currency (22 options, defaulting to your site currency).

  • Subscription — up to four billing options, each with interval, price and minimum committed periods. This block also holds an Enable Stripe Customer Portal switch that does nothing: it saves, but nothing acts on it. Subscriptions are managed from the member area.
  • InstallmentsNumber of Installments (2 to 24) and Installment Frequency (Monthly or Quarterly).
  • VoluntaryMinimum Amount, default 1. Below 1.00 the gateway call is rejected outright. Set it to 0 and a buyer entering 0 goes to the free-registration form instead of a payment page.

Stripe — only the TEST Mode / LIVE Mode switch and read-only Stripe IDs. Every new product is created in TEST Mode, on sandbox keys, taking no real money. Despite living on the Stripe tab and describing itself in Stripe's terms, this switch is the product's mode for both gateways — PayPal orders, subscriptions and plans run against PayPal's sandbox for as long as the product sits in TEST Mode. If you sell through PayPal only, this is still the switch you must flip, and it is easy to miss because nothing on the PayPal side mentions it. It is per product, so one product can go live while its sibling stays quietly in test. If sales are not appearing, check this first.

Cost & Profit — your cost to fulfil, snapshotted onto each sale; this is what makes "refund minus cost" work later.

Permission — the string that unlocks content, granted on payment; the content lives at /myarea/mycontent/<slug>. Leave it empty and the confirmation email carries no access link, and the member-area page redirects to a route that does not exist: the buyer sees a 404, not a message.

After purchase — Success message, Next steps, and an optional Upsell product.

Build the lessons with the Builder button on the product's card; without content, the access link lands on an empty placeholder.

Publish it

A new product is a draft and /products/<slug> returns 404 until you publish. The switch is not in the dialog: it is the button at the bottom of the product's card in the list, reading Draft at rest and Publish on hover. Sales Page and Member Page stay greyed out until then. Show on products page, on the General tab, separately controls catalogue listing.

Coupons

Admin → Products → Coupons tab → Add Coupon. Coupons live in Lasersite's own database; Stripe gets a throwaway discount per checkout session. Set a code (or generate an 8-character one) and a Name — both are required and saving is refused without them; the name is internal, the code is what the buyer types. Then a Discount Type — Percentage, Fixed Amount or Free Access — and value, then usage limits, a minimum purchase amount, an optional date range, and Scope: global, or named products and event templates.

  • Payment Type Restrictions says "Leave empty to allow all payment types", but a new coupon arrives with Paid, Subscription and Installments ticked and Voluntary Amount not. On a pay-what-you-want product the code is refused until you tick Voluntary Amount or clear all four.
  • A Free Access coupon is checked against the product's primary payment type, not the one the buyer picked — so on a multi-type product that restriction can reject a code that should have worked.
  • Codes match case-insensitively, and per-contact limits count by email address — one person with two addresses gets two uses.
  • A coupon reserved for named contacts fails closed: with no email entered, the buyer is told it is reserved and asked for the address it was issued to.
  • A global coupon can be switched off for one product without losing its global scope. Coupons are refused on free products entirely.
  • Free Access skips the gateway and sends the buyer to a free-registration form; it is re-checked server-side, so the code cannot be faked.
  • The label on the Stripe checkout page is the coupon CODE, not the name you gave it. Code INTERNAL-TEST-40 is what the buyer reads — which is the practical reason to keep the internal wording in Name and the customer-facing wording in Code.
  • Max Uses is checked before the buyer reaches the gateway, but the counter only increments when payment completes. Two people starting checkout on the last use both pass — not a hard limit on something scarce.

Fixed-amount coupons carry three defects. The discount takes your site's default currency — there is no currency field on the form — while the line item is priced in the product's, so a non-EUR product mismatches at Stripe. On a multi-plan subscription it is computed from the product's base price and interval, not the plan the buyer chose, on both gateways. On a PayPal subscription it discounts every cycle forever, where Stripe's stops after a calculated number of periods. Percentage coupons on a single-plan product have no known surprises.

What happens after a payment

Both gateways feed one fulfilment path, and a repeated webhook is ignored rather than fulfilled twice. Two automations are active out of the box: Purchase Confirmation (order number, access link, invoice link), which re-sends on every purchase, and the account Welcome Email, which sends once per contact. Renewals and instalments use a separate template, switched by Receipt email for recurring charges on General Settings, General tab.

Buying does not create a login. Contacts and user accounts are separate, and the only route to an account in the purchase flow is on the success page. With no account on that email it offers a password field (minimum 8 characters); with one it offers sign in instead and never a password field — deliberately, since setting a password on an existing account by buying something would be a way in. A buyer who closes that tab cannot reach their content or their invoice until they get a login another way. Say so on the success page.

Free and comped registrations take a weaker path. A free signup, or a purchase comped with a Free Access coupon, skips that path. The permission is granted and the confirmation email still carries the order number and — if the product has a permission set — the access link. What is missing is the invoice link: that placeholder renders empty, because a zero-value registration is never invoiced. If you comp access, expect to follow up by hand for anyone who asks for an invoice.

Invoices, refunds and cancellations

Invoices are numbered 2026-0001; test-mode sales draw from a separate TEST-2026-0001 series, so rehearsing never burns a live number. An invoice is issued once and frozen, and only a completed, partially refunded or disputed purchase above zero gets one — free signups never produce an invoice. Customers download theirs from /myprofile/orders/<id>/invoice while signed in.

Admin → Purchases lists transactions and refunds three ways on both gateways: full, full minus your recorded fulfilment cost, or custom. The refund is only half-synchronous — Lasersite calls the gateway and returns; the status change is written when the gateway's webhook comes back. If that webhook never arrives, the money has left but the sale still shows as completed, so check the gateway dashboard before refunding a second time.

Customers cancel their own subscription from the member area, but a minimum-periods commitment is enforced first; access then runs to the end of the paid period. Manual sales and free signups both store the provider as "stripe" because neither path sets it, so do not read that field as proof of how someone paid. A product with purchases against it cannot be deleted, only archived — deleting would cascade and erase the sales, payments and referrals behind it.

Before you go live

  1. Invoice details and tax rate on the General tab; business name, address and statement name on the Branding tab. Both live under General Settings — in the admin menu Settings is only the group heading, the entry you click is General Settings.
  2. Gateway enabled in Admin → Integrations, Test Connection green — and for Stripe, the live secret key saved as well as the test one, or checkout will not offer Stripe at all and step 4 cannot be done.
  3. Product built, permission set, content in the builder, After-purchase copy written.
  4. A full test purchase in TEST Mode — the sale appears, both emails arrive, the permission is granted, the content opens, the invoice downloads.
  5. The TEST Mode / LIVE Mode switch on the Stripe tab flipped to LIVE Mode. Per product — and it governs PayPal too, not just Stripe.
  6. The product published. Drafts 404.
  7. If any product uses Stripe payment plans, arrange the recurring job that collects them. Without it you charge payment 1 and never payment 2 — there is no built-in scheduler and nothing warns you. Whoever runs your server calls GET /api/installments/process on a schedule with an Authorization: Bearer <secret> header; it takes up to 50 due payments per call. Set CRON_SECRET explicitly — leave it unset and the value falls back to something derived that you will not be able to guess, so the calls come back 401. PayPal plans are unaffected.

A product's currency stays editable after launch. Changing it creates a new price object at the gateway, and sales already made keep the currency they were made in.

Was this helpful?

Comments

Selling products and courses | lasersite.ai