Taking payments (the user's own shop)
How to take payments in an app on LazyFrog with your own Stripe account: customers pay you directly and LazyFrog never touches the money.
- Customers pay the user's own payment account (Stripe; or PayPal, Paddle, Lemon Squeezy): the user is the seller, and LazyFrog never holds their money. That has nothing to do with LazyFrog billing (Account › Billing is the user's LazyFrog plan): say so if they mix them up. These providers are reachable on every plan.
- Where the business is: Stripe serves about 46 countries (the UK, the EU, the US and
more), but not South Africa: there, use Paystack (owned by Stripe; Checkout-like hosted payments, its
own webhooks signed with
x-paystack-signature), or PayFast, Yoco or Peach. Ask where the business is registered before choosing. - Marketplaces (a commission on payments between users): Stripe Connect with destination
charges (
application_fee_amount,transfer_data.destination), Express onboarding withaccount.updated, bookable only once the seller'spayouts_enabledis true, a payout schedule, a webhook for connected accounts' events, and refunds that reverse the fee. Who is the merchant of record, and tax, are the user's decisions: ask. Stripe Connect doesn't serve every country (South Africa: Paystack split payments, PayFast, Yoco, Peach; reachable on every plan). - A SaaS whose customers are the sellers (a ticketing app for promoters, a booking app for
salons): each customer connects their own Stripe account, so they are the merchant and the
money never passes through the user. Stripe Connect with Standard accounts and direct charges
(the
stripeAccountoption on each call), Account Links for onboarding, sales open only onceaccount.updatedsayscharges_enabled, and each event'saccountchecked against the tenant it's for. The user's own platform key is the onepayments connecttakes (a restricted key with Write on Connected accounts, Account links, Checkout Sessions and Refunds);payments webhookwithconnected_accounts: truemakes the endpoint for their customers' accounts (its secret isSTRIPE_CONNECT_WEBHOOK_SECRET). - Selling limited places (tickets, seats, classes): hold the places in the database with
the Checkout session (row locks or a constraint, so two buyers never get the last one). A
session's
expires_atis at least 30 minutes away, so a hold lasts at least that long; release holds oncheckout.session.expiredand from a cron (missed events), and when a payment arrives after its places went to someone else, refund it at once and say so. - Subscriptions (a SaaS's plans): Checkout in
subscriptionmode, withtrial_period_days(or a trial without a card, ended by the app); handlecheckout.session.completed,customer.subscription.created/updated/deletedandinvoice.payment_failed, and tie each to the tenant throughclient_reference_idor metadata; send people to Stripe's Billing Portal to change cards or cancel; decide what a lapsed trial does (read-only, a banner) and run it from a cron. Test mode works against the live address before launch. - Use a hosted checkout (Stripe Checkout) so card details never touch the app; Payment Links suit a handful of products with no code. Prices come from the database, never from the browser.
- Stripe through the
paymentstool:payments connect(env preview) gives the user a link to paste a restricted key in test mode (rk_test_…), and says what to tick at Stripe; the key never passes through you.payments statuschecks it with Stripe (test or live, restricted or full, the account's country) and warns about a live key on preview or a test key on production. When the app has its webhook route,payments webhookmakes the endpoint on their Stripe account for that environment's address and keeps its signing secret asSTRIPE_WEBHOOK_SECRET. For the live site, the same with env production and a live key (rk_live_…) when they're ready to sell. Until a key is set, the app says "payments aren't set up yet" instead of failing. Paystack and others:secrets requestfor their keys, and their dashboard for the webhook. - The webhook route: read the raw body, check
Stripe-SignaturewithSTRIPE_WEBHOOK_SECRET, keep the event ids so a repeat does nothing, mark orders paid only from it, and answer 2xx quickly (a sleeping site wakes for it; Stripe retries for 3 days). A preview password blocks webhooks to the preview: test without one, or on the live site. The preview and the live site each have their own endpoint and signing secret (payments webhookfor each env), androtate_preview_urlchanges the preview's address: runpayments webhookagain after it. - Tell them in plain words what to do at Stripe: make an account (testing needs no bank details),
stay in Test mode, create the restricted key
payments connectdescribes and paste it into the link (never into the chat), test with card 4242 4242 4242 4242, and switch to live mode to sell. - A shop needs terms of sale, refunds and privacy pages: placeholders the owner fills in.
For your AI: this page as Markdown · llms.txt