Operating sales connections
Operating sales connections
A successful connection receives a provider event, matches a linked product, issues the expected license quantity, assigns the buyer, and delivers a key when email delivery is enabled. Verify each step separately. A provider's HTTP 200 proves receipt, and an Active connection proves a successful fulfillment has happened; neither guarantees every later event succeeded or an email reached an inbox.
Email and ownerless licenses
Automatic license emails require an eligible LicenseSeat plan, Settings → Organization → Email license keys to my customers enabled, and a valid buyer email. If delivery is disabled, licenses still issue. Check the license and email delivery separately during testing, including spam filtering. Local development can use a mail catcher instead of real inbox delivery.
An order with no email can issue an ownerless license. An organization owner/admin can open it, use Assign customer, enter the buyer's email and optionally request a license email. The email option respects the organization's plan and delivery setting. Assignment cannot replace an existing owner. Ownerless licenses can also be revoked from their license page or by a correlated refund.
Paddle is different: transaction events normally have only a customer ID. LicenseSeat waits for signed customer history or checkout custom data to supply the email; subscribe to its customer events.
Subscription access
Use a finite license plan whose duration matches the billing interval. Initial purchases grant the plan's duration. Free-trial signup can grant this duration too: automatic synchronization of trial ends or the initial provider billing period is not provided. A subscription mapped to a perpetual plan still issues a license, preserving existing seller configurations. When the purchase identifies a subscription, its event shows a Subscription plan warning in the event list and detail page. Order-only payloads may not identify a subscription yet, so review the mapping before selling. Cancellation does not revoke perpetual access. Changing a mapping does not retroactively change existing license expiry.
Stripe, Paddle and Polar renewals use the matching provider billing-period end without shortening access already granted. Gumroad and Lemon Squeezy renewals use the provider payment timestamp plus the license plan duration. A fixed day count does not exactly model every calendar month; configure it deliberately and test expected dates. Cancellation, a failed payment or a plan-change event does not automatically revoke or change plans. Without another renewal, finite access ends at the license's stored expiry. Existing perpetual licenses stay perpetual: Stripe/Paddle/Polar renewal targets do not shorten them; Gumroad/Lemon Squeezy renewals on active perpetual licenses are acknowledged without inventing a finite expiry, with a warning on the event. Refunds can still revoke them.
Shopify paid orders are treated as one-time purchases; selling plans and subscription apps are not synchronized.
Polar subscriptions renew through order.paid with the subscription_cycle billing reason. Initial access follows the mapped plan duration, including trials. Cancellations, pauses and revocations are ignored; finite access ends at its stored expiry, while perpetual access remains. Initial seat quantity is automated; later seat changes and member assignments are not synchronized. See the Polar guide for these limits.
Refunds/disputes can revoke the whole correlated subscription, including access paid for by later invoices. Partial-refund rules differ by provider: consult its guide. Winning a dispute does not automatically reinstate access. A revoked license is not restored by an ordinary renewal.
Test before taking real payments
- Create the provider's sandbox/test destination and use its own secret and product IDs. Use a separate LicenseSeat organization when you need full separation: mappings are shared across connections for the same provider within an organization.
- Link the product before making the purchase. Synthetic provider samples often use unrelated product IDs or omit buyer information.
- Verify receipt, processed status, product/plan, license quantity, owner, expiry and email delivery. A signed simulation can create real LicenseSeat licenses and send real emails; it is not automatically a dry run. Gumroad
test=truepings are the exception: only the connection's received timestamp changes. - Test a refund and check the license becomes revoked. For subscriptions also test a renewal and a refund/dispute of a renewal.
- Repeat the setup with live IDs and secrets before selling. A successful test destination does not prove live delivery. Revoke your test licenses afterwards.
Recover a missed purchase, renewal or refund
LicenseSeat stores accepted events before background processing. Provider delivery retries and LicenseSeat processing retries are separate. Processing has finite automatic attempts. A periodic recovery job re-enqueues receipts left pending and renewal/customer-history failures when newer history for the same organization/provider arrives. Unmatched refunds and disputes are Ignored, with an explanation that no matching license was found; they do not consume repeated job attempts or create red failures for unrelated merchandise. Their signed payloads are retained. Every five minutes, the recovery job checks at most 100 eligible events, rotating checked unmatched reversals to the back of the queue. It enqueues an unmatched reversal only when retained history now resolves it to an actual license. Larger backlogs can take several sweeps. A later purchase also checks retained reversals before emailing an active key. The job does not invent missing provider data or continuously restart malformed events.
Open the event's detail page from the connection's event list and inspect its status and error:
- No fulfillment target / no active mapping: link the correct ID, then use Retry on the original ignored purchase. Duplicate-fulfillment events cannot be retried into additional licenses.
- Ignored refund/dispute with no matching license: for an unlicensed product, no action is needed. For a licensed purchase, recover the matching purchase/payment history; the retained reversal can then resolve automatically, or use Retry Processing. Unrelated new sales do not restart it.
- Missing purchase or subscription: resend the original purchase and subscription history from the provider, then retry the renewal/reversal. Manually issuing a license with the same email does not link it to the provider subscription.
- Stripe subscription refund/dispute: on Basil and later, subscribe to
invoice_payment.paid, replay that relationship event and the associatedinvoice.paidor Checkout history, then retry the reversal. Relationship events may appear ignored while still providing correlation history. - Paddle awaiting customer history: replay the customer notification or use checkout custom data for future transactions. A no-op customer save is not guaranteed to generate a new event.
- Invalid data, ambiguous mapping or incompatible plan: correct the source/configuration and retry the relevant event. Read the error instead of repeatedly replaying unchanged input.
- Old refund marked processed but access still active: processed reversal events expose Retry for repair of historical unmatched refunds. Reprocessing a matched reversal is idempotent. Retained reversals are also checked before a newly arriving purchase can email a fresh active key.
If the provider no longer retains the required history, manage the affected license manually. There is no automatic import of pre-existing subscriptions. For urgent refunds, revoke the known license directly while resolving the event history.
References
- Stripe delivery ordering and retries
- Stripe Invoice Payment object
- Paddle webhook delivery
- Shopify HTTPS delivery
- Polar webhook delivery
- Lemon Squeezy webhook events
- Gumroad Ping
Provider documentation is authoritative for their wire contracts and dashboards. This guide describes LicenseSeat's access and recovery policy; provider features are not automatically supported just because the provider offers them.