Selling in your app
Any app on Flitzy can sell access: a monthly or yearly subscription, or a one-time purchase. You connect your own Stripe account once; customers pay into it, and Stripe pays out to your bank account. Flitzy keeps 5 % of each payment. Stripe’s own fees are charged to your Stripe account.
You are the seller: the product, the customers and the payments live in your Stripe account, where you can also see payouts and issue refunds.
Set it up
Section titled “Set it up”-
Connect Stripe. In the dashboard, open Plan and press Connect Stripe account, or run:
Terminal window flitzy billing connectStripe asks for your details and a bank account. Payments can start once Stripe has checked them, usually within minutes;
flitzy billing statusshows where it stands. In a team, only its admins can do this, and the account belongs to the team. -
Set a price for the app. On the app’s page under Selling, or:
Terminal window flitzy billing enable --app notes --price 9.99 --interval month--intervalismonth,yearoronce(one-time purchase);--currencyiseur(default),usd,gbporchf. Running it again changes the price for new customers; existing subscriptions keep theirs. -
Add the buy button and check who paid in your code, as shown below. Flitzy put these variables into the app, which restarted:
Variable FLITZY_APP_PAYWALL_URLBase URL of your paywall, e.g. https://api.flitzy.app/v1/paywalls/pw_…FLITZY_APP_PAYWALL_IDIts id. FLITZY_APP_PAYWALL_SECRETFor checks from your server. Never send it to the browser. STRIPE_ACCOUNT_IDYour Stripe account, for Stripe.js if you want it. STRIPE_PUBLIC_KEYFlitzy’s publishable key, for Stripe.js together with STRIPE_ACCOUNT_ID.
The buy button
Section titled “The buy button”Ask Flitzy for a checkout and send the customer there. This call works from the browser; Stripe’s page handles the payment and sends the customer back to your app.
// ref: how your app knows this customer later, e.g. your user idasync function buy(ref) { const r = await fetch(`${PAYWALL_URL}/checkout`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ref, // optional email: currentUser?.email, // optional, prefills Stripe success_url: `${location.origin}/thanks`, // default: your app's start page cancel_url: `${location.origin}/pricing`, }), }); const { url } = await r.json(); location.href = url;}PAYWALL_URL is the value of FLITZY_APP_PAYWALL_URL; hand it to your frontend however your app passes config (it is not secret). Return URLs must be on your app’s own addresses or http://localhost.
After paying, the customer comes back to success_url with ?session_id=cs_… (send Referrer-Policy: no-referrer on that page if it loads third-party scripts). GET $FLITZY_APP_PAYWALL_URL/sessions/<session_id> answers {paid, ref, email}, so the page can say thanks right away.
Who has paid
Section titled “Who has paid”Check from your server, with the secret, before serving paid content:
async function hasPaid({ ref, email }) { const q = ref ? `ref=${encodeURIComponent(ref)}` : `email=${encodeURIComponent(email)}`; const r = await fetch(`${process.env.FLITZY_APP_PAYWALL_URL}/access?${q}`, { headers: { Authorization: `Bearer ${process.env.FLITZY_APP_PAYWALL_SECRET}` }, }); return (await r.json()).active === true;}
app.get('/pro/*', async (req, res, next) => { if (await hasPaid({ ref: req.user.id })) return next(); res.redirect('/pricing');});import os, requests
def has_paid(ref): r = requests.get(f"{os.environ['FLITZY_APP_PAYWALL_URL']}/access", params={"ref": ref}, headers={"Authorization": f"Bearer {os.environ['FLITZY_APP_PAYWALL_SECRET']}"}, timeout=5) return r.json().get("active") is TrueThe answer: {active, kind: "subscription" | "payment", status, currentPeriodEnd, cancelAtPeriodEnd, email, ref}. Subscriptions count as active while Stripe says active, trialing or past_due; one-time purchases stay active unless they are refunded in full or disputed.
Prefer ref with the id of your signed-in user. The email is whatever the buyer typed into Stripe Checkout and is not verified, so only look people up by email if your app has verified it too.
Let customers manage and cancel
Section titled “Let customers manage and cancel”Customers in the EU must be able to cancel a subscription online. From your server, get them a link to Stripe’s customer portal:
const r = await fetch(`${process.env.FLITZY_APP_PAYWALL_URL}/portal`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.FLITZY_APP_PAYWALL_SECRET}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ ref: req.user.id, return_url: 'https://notes.flitzy.app/account' }),});res.redirect((await r.json()).url);Good to know
Section titled “Good to know”- Stopping: Stop selling (or
flitzy billing disable --app notes) means nobody new can buy. Customers who already paid keep access until their subscription ends. - Test mode: while Flitzy runs Stripe in test mode, onboarding accepts test data and card
4242 4242 4242 4242pays without charging anything. - You are the seller: put your own imprint, terms and cancellation policy in the app; Flitzy’s terms explain the split.
- Activity: every purchase shows up in the activity log of the app.
- A leaked secret:
PUT /v1/apps/<app>/monetizationwith"rotateSecret": true(and the current price) puts a newFLITZY_APP_PAYWALL_SECRETinto the app; the old one stops working.