Payment Stack for Solo Founders: Stripe, Paddle, Lemon Squeezy, or WeChat Pay?

"Paddle: provision access and handle subscription state with webhooks"
Disclaimer: This article does not provide tax, legal, company-registration, foreign-exchange, or entity-eligibility advice. For Merchant of Record arrangements, VAT/GST/sales tax, domestic or overseas entities, and payout routes, rely on provider terms and qualified professional advice.
Your pricing.ts defines starter_monthly, pro_yearly, lifetime_license, and wechat_one_time, but the database has only one is_paid field. A checkout.session.completed webhook arrives and the customer returns through success_url, yet entitlements is still empty. The problem is not the payment button. The payment system has failed to connect products, orders, subscriptions, and access rights.
A solo founder should answer five questions before choosing a provider: What are you selling? How is it billed? Who is buying it? Who owns the transaction and sales-tax responsibilities? Who grants access after payment? Stripe, Paddle, Lemon Squeezy, and WeChat Pay are not four equivalent buttons. They cover different layers and responsibilities.
Define the Sales Model Before Choosing a Payment Provider
One-time purchases revolve around orders and delivery. SaaS subscriptions require the full billing lifecycle. Usage-based billing also needs traceable usage data. Put the model into products, prices, and local tables before comparing providers.
| Sales model | Starting points to evaluate | Key asynchronous events | Core local tables |
|---|---|---|---|
| One-time digital product | Stripe / Paddle / Lemon Squeezy | checkout.session.completed / transaction.completed / order_created | orders + entitlements |
| SaaS subscription | Stripe Billing / Paddle Billing / Lemon Squeezy | customer.subscription.* / subscription.* | subscriptions + entitlements + usage_events when metered |
| Hybrid subscription and one-time sales | Stripe Billing / Paddle Billing | Multiple event types | orders + subscriptions + entitlements |
| Mainland China or WeChat ecosystem | WeChat Pay (JSAPI/H5/Native) | Payment callback and order-query result | orders + wechat_prepay |
Keep three points in mind:
- A one-time product primarily needs orders, fulfillment, refunds, and redelivery. It does not need the full subscription lifecycle.
- A SaaS subscription needs a
subscriptionstable withcurrent_period_start/end,cancel_at, andstatus. Metered billing also needs auditableusage_events. - WeChat Pay is a payment rail and merchant system, not a replacement for a global Merchant of Record or SaaS billing platform.
Stripe Billing, Paddle Billing, and WeChat Pay capabilities can change. Before implementation, recheck account region, product mode, payment-method eligibility, API version, and provider terms.
A Merchant of Record Does Not Remove Every Responsibility
A Merchant of Record, or MoR, is the seller of record for a transaction. Paddle and Lemon Squeezy both use the Merchant of Record model for eligible digital products and handle payments, sales tax, refunds, or disputes within the scope of those transactions. This reduces global sales-tax and billing operations, but it does not eliminate the creator’s or company’s income-tax, entity, product-compliance, data-protection, and accounting obligations.
With the Stripe route, the merchant normally remains the seller of record. Stripe Tax can help calculate sales tax, VAT, and GST and provide threshold-monitoring and registration-related tools, but it does not automatically make Stripe your Merchant of Record. Registration, filing, and entity responsibilities depend on the jurisdiction and transaction.
Do not choose an MoR from a fixed revenue threshold. Compare these dimensions instead:
| Dimension | Self-managed payment and billing stack | Merchant of Record |
|---|---|---|
| Customization | Combine Checkout, Billing, Tax, invoicing, and internal workflows | Follow the platform’s product policy, checkout, contract, and settlement rules |
| Tax and billing operations | The merchant confirms registration, filing, invoicing, refunds, and dispute processes | The MoR assumes sales-tax, payment, and selected compliance work for transactions in scope |
| Cost model | Include tax tooling, engineering, finance, and support in addition to processing fees | Evaluate settlement, refunds, add-on fees, and platform limits, not only the platform percentage |
| Best fit | Strong customization, an existing operations function, or special contract flows | Reduced global sales-tax and subscription-operations work for eligible products |
The final contract and tax boundary depends on the entity, jurisdiction, product, and customer type. Marketing pages describe product positioning; they do not replace provider terms or professional advice.
Choosing Between Stripe, Paddle, Lemon Squeezy, and WeChat Pay
If you want subscriptions and WeChat Pay, split the problem first. Subscription lifecycle, global payments, and mainland-China payment coverage do not have to come from one provider. A payment method appearing on a platform does not mean it works for every account region, Checkout mode, or recurring flow.
| Provider | Responsibility model | Subscriptions and one-time sales | China payment scenarios | Native licensing | Good starting point |
|---|---|---|---|---|---|
| Stripe | Payment, Billing, and Tax tools; normally not the MoR | Checkout and Billing with extensive customization | Alipay/WeChat Pay depend on account region, currency, and product mode | No general License Key product | SaaS products that need control over payments, subscriptions, tax tooling, and internal flows |
| Paddle | Merchant of Record | Paddle Billing and Checkout | Check current Dashboard and documentation eligibility by account and region | Application maintains entitlements | Software businesses that want less global sales-tax and subscription-operations work |
| Lemon Squeezy | Merchant of Record | One-time digital products, straightforward subscriptions, and metered billing | One-time checkout can show Alipay/WeChat Pay; subscription methods are more limited | License Keys | Digital products, licenses, and early subscriptions |
| WeChat Pay | Payment rail and merchant system | JSAPI/H5/Native payment scenarios; billing lifecycle is self-managed | Mainland China and the WeChat ecosystem | None | RMB one-time purchases and WeChat-based checkout |
The following points were confirmed in official documentation on July 18, 2026:
- Stripe Checkout supports hosted pages, embedded pages, and composable components. Payment methods depend on region, currency, and Checkout mode.
- Paddle webhooks use at-least-once delivery. Paddle retries when an endpoint does not return
200within five seconds. Events can be duplicated or arrive out of order, so deduplicate withevent_idand useoccurred_atwhen reasoning about sequence. - Lemon Squeezy currently lists Cards, PayPal, Apple Pay, Google Pay, Alipay, WeChat Pay, Cash App Pay, and bank debits. Subscription products currently support only Cards, Apple Pay, Google Pay, and PayPal.
- A WeChat Pay H5 flow requires server-side order creation, payment callbacks, and active order queries. A browser redirect alone is not authoritative.
Fees, payment methods, settlement schedules, supported countries, and product policies can all change. Open the provider’s current pricing and contract pages when building the final budget instead of copying an old percentage from an article.
Webhooks Are the Entitlement-Sync Boundary
Consider two common failures:
checkout.session.completedarrives andsuccess_urlredirects, butentitlementsis not updated, so a paying customer still cannot use the product.- The same event reaches
webhook_eventstwice, and the handler issues two licenses.
Both failures come from treating one HTTP request or a success page as final business truth. Payment events can be duplicated, delayed, or delivered out of order. Some states also require an order query or a later event for confirmation.
Webhook Endpoint Design Principles
| Principle | Stripe | Paddle | Lemon Squeezy | WeChat Pay |
|---|---|---|---|---|
| HTTPS endpoint | Required | Required | Required | Required |
| Signature verification | Stripe-Signature | Paddle-Signature | X-Signature | WeChat Pay API v3 signature |
| Idempotency key | Event ID or business-object ID | event_id | Event type + object ID or a custom unique key | out_trade_no and provider transaction ID |
| Response strategy | Verify and persist the event, then respond quickly and process asynchronously | Return 200 within five seconds | Return success, then process asynchronously | Follow the current API response contract |
| Recovery path | Query payment or subscription state | Query entities and reconcile | Query order or subscription state | Query orders, reconcile statements, and support manual recovery |
The operating rules are straightforward:
- A webhook or payment callback is the entitlement-sync entry point.
success_urlshould display “processing,” not grant access. - Verify the signature first, then store the raw event or required fields in
webhook_events. Move complex business work to an asynchronous job. - Enforce idempotency with a unique constraint. Record
event_id,source,occurred_at,processed_at,status, andpayload_hash. - For out-of-order delivery, compare provider event time, object update time, or state version. Do not overwrite state based only on request arrival order.
- Run reconciliation periodically, query order or subscription state, and keep a manual recovery path.
Orders, Subscriptions, Entitlements, and Events
| Table | Core fields | Stripe mapping | Paddle mapping | Lemon Squeezy mapping |
|---|---|---|---|---|
orders | provider_order_id, customer_id, amount, currency, status, created_at | Checkout Session / PaymentIntent | transaction | order |
subscriptions | provider_subscription_id, customer_id, status, current_period_end, cancel_at | subscription | subscription | subscription |
entitlements | user_id, product_id, feature_key, source, status, expires_at | Derived from an order or subscription | Derived from a transaction or subscription | Derived from an order, subscription, or license |
webhook_events | provider, event_id, occurred_at, processed_at, status, payload_hash | Idempotency and audit | Idempotency and ordering | Idempotency and audit |
Do not copy every object from one provider’s API into local tables. Define the stable fields needed for access checks, then store provider object IDs for queries and reconciliation.
Entitlement Synchronization Strategies
| Strategy | When to use it | Implementation notes |
|---|---|---|
| Lean cache | Most subscription SaaS products | Store only the customer, subscription, status, price, and product fields needed for access checks. Keep them current with provider events. |
| State mirror | Offline billing views or complex operations dashboards | Replicate more subscription data, track update time, and reconcile to prevent local drift. |
| License key | One-time digital products or desktop software | Save the instance ID after activation and validate store, product, variant, and customer mappings. A license key is not a complete user system. |
Paddle’s official provisioning documentation recommends a lean cache for most applications. Move to a state mirror only when richer local queries are necessary. Lemon Squeezy license keys also require application-side validation of product and customer data and a mapping from each instance to your account and device model.
Provider-Specific Implementation Notes
These notes define the first implementation boundary. They do not replace each provider’s complete integration documentation.
Stripe Implementation Notes
An early SaaS product can start with hosted Checkout and Customer Portal rather than maintaining a custom card form. Stripe Billing handles lifecycle capabilities such as subscriptions, invoices, usage-based billing, and revenue recovery. Stripe Tax is a tax calculation and workflow tool, not a Merchant of Record.
Products and prices must map to local entitlements: product_id represents a product or access package, while price_id represents monthly, annual, per-seat, or usage pricing. Do not leave only is_paid on the users table.
For an implementation example, see the Next.js cart and Stripe payment tutorial, which covers Checkout Sessions, a webhook endpoint, and order handling.
Paddle Implementation Notes
First confirm that a tutorial targets Paddle Billing rather than Paddle Classic. Their APIs, webhooks, Paddle.js versions, and Product/Price models differ.
Paddle Checkout presents the checkout, but your application still owns provisioning. Most applications only need the customer, subscription, status, price, product, and scheduled-change fields involved in access decisions. Build a state mirror only when the operations interface truly needs complete billing data.
Whichever cache model you choose, update it through webhooks and run reconciliation. Using a Merchant of Record does not make the application automatically know who can access each feature.
Lemon Squeezy Implementation Notes
Lemon Squeezy is a practical starting point for early digital products, licenses, and relatively simple subscriptions. It provides a Merchant of Record, checkout, subscriptions, usage-based billing, webhooks, and License Keys. Confirm actual fees and support against the current store plan and documentation.
After activating a license key, save the instance ID and validate store_id, product_id, variant_id, and the customer. A key for another product or a resold key must not map directly to a Pro entitlement.
If the requirement is a WeChat Pay subscription, verify subscription payment methods separately. The current documentation lists WeChat Pay and Alipay as available payment methods, but subscription products support only Cards, Apple Pay, Google Pay, and PayPal.
WeChat Pay Boundaries
WeChat Pay works well for mainland-China and WeChat checkout, but it is not a global Merchant of Record and does not provide a complete SaaS billing lifecycle. The merchant still needs order state, callback signature verification, order queries, refunds, reconciliation, invoicing, and entitlement synchronization.
H5, JSAPI, Mini Program, and Native are payment scenarios, not separate subscription systems. In an H5 flow, the backend creates an order and passes h5_url to the frontend. When the browser returns, the backend still queries the order and applies the payment callback to the order identified by out_trade_no.
Confirm product permissions, merchant entity, domains, fees, and API parameters against the current WeChat Pay merchant documentation.
Next Step: Turn the Payment Button into a Testable State Machine
After choosing providers, break the integration into testable engineering tasks:
- Create
orders,subscriptions,entitlements, andwebhook_events. Addusage_eventsfor metered billing. - Implement signature verification, idempotency, out-of-order handling, fast acknowledgment, and failure recovery for every webhook or payment callback.
- Make the success page query local order state instead of setting
is_paid=true. - Add tests for provider queries, reconciliation, refunds, failed renewals, and manual recovery.
- In the sandbox, resend events and deliver state updates out of order. Verify that access is neither granted twice nor rolled back incorrectly.
For backend deployment and database choices, continue with the Supabase Edge Functions guide and the backend and database articles in this series. Completion is not a successful payment-page redirect. It is the point where orders, subscriptions, and entitlements converge on the correct state despite duplicates, delays, out-of-order delivery, and refunds.
Choose and Implement a Solo Founder Payment Stack
Start with the sales model, responsibility boundary, and target market, then choose providers and build an auditable entitlement-sync path.
⏱️ Estimated time: 45 min
- 1
Step 1: Define the sales model
Specify whether the product uses a one-time purchase, SaaS subscription, usage-based billing, or a hybrid model. Document refunds, renewals, upgrades, downgrades, and access end dates. - 2
Step 2: Assign tax and operational responsibilities
Decide whether to combine payment, billing, and tax tools yourself or use a Merchant of Record. Confirm entity and tax responsibilities against provider terms and professional advice. - 3
Step 3: Choose payment rails for each market
Evaluate Stripe, Paddle, and Lemon Squeezy for global card payments and subscriptions. Evaluate WeChat Pay for one-time purchases in mainland China or the WeChat ecosystem, checking account region, product category, and payment-method eligibility. - 4
Step 4: Build the local state model
Create orders, subscriptions, entitlements, and webhook_events. Use unique provider event or order IDs for idempotency and auditing. - 5
Step 5: Test asynchronous entitlement updates
Test signature verification, duplicate events, out-of-order delivery, timeouts, refunds, failed renewals, and manual recovery. The success page should display processing status, not grant access.
FAQ
What is the main difference between Stripe, Paddle, and Lemon Squeezy?
Should a solo founder start with a Merchant of Record or Stripe?
Will Paddle or Lemon Squeezy automatically enable SaaS access?
If Lemon Squeezy supports WeChat Pay, can it run WeChat Pay subscriptions?
Can WeChat Pay replace Stripe for global SaaS billing?
How should an application handle duplicate, out-of-order, or missing webhooks?
What tables does a minimum payment system need?
11 min read · Published on: Oct 21, 2026
Solo Founder Tech Stack Guide: Build, Automate, Ship, and Grow
If you landed here from search, the fastest way to build context is to jump to the previous or next post in this same series.
Previous
Choosing a Solo-Founder Database: D1, Postgres, R2, S3, or SQLite
Choose D1, Postgres, R2, S3, or SQLite by classifying business records, events, files, caches, local data, and backups, then checking cost and migration signals.
Part 8 of 10
Next
Building and Launching a WeChat Mini Game from Scratch with AI: Writing Code Was the Easy Part
A retrospective on how an indie developer with zero game dev experience built and launched 'English Word Bento Box' using AI and Cocos Creator.
Part 10 of 10



Comments
Sign in with GitHub to leave a comment