Vibes DIY
Vibes DIY / Docs
creator docs · guide · payments

Take payments with Stripe

A vibe can take money. Ask for a deposit, tickets, dues, a shop with checkout or a monthly membership, and the builder writes the part that talks to Stripe, keeps the card on Stripe's own page, and keeps the record of who paid in your app. You bring one thing: your Stripe account. Everything a buyer pays lands there.

This page is what that looks like, what to ask for, what you set up once, and where the edges are. There are two recipes, because money that happens once and money that keeps coming are different shapes.

What a vibe is good at

Money the maker already has a reason to collect. The apps that take payment best are the ones where the people and the thing already exist: a booking page for clients you already have, dues for a club with a roster, a ticket for an event with a date, a members-only feed for people who already read you. The payment is one more column on a record the app already keeps.

The card never touches your app. Checkout is a page Stripe hosts. Your app opens it in a new tab, Stripe takes the card, handles Apple Pay and Google Pay and whatever your account turns on, and sends the buyer back. Nothing about a card is ever in your app's code or its data. That keeps your app out of the card-handling scope that Stripe's own pages carry for you; what still applies to you as a merchant is the short self-assessment Stripe asks of hosted-checkout accounts, and your Stripe dashboard tells you when it does.

"Paid" is a fact only Stripe can establish. When the buyer comes back, your backend reads the payment back from Stripe with your key before it marks anything paid, and it checks that the payment is for this order, at this amount. A browser cannot mark an order paid, and neither can a guessed link. If a buyer pays and closes the tab without coming back, a sweep every few minutes reads their payment back anyway.

You see every order in your own app. Who paid, what for, how much, when. It is also in your Stripe dashboard, and the two agree because the app only ever copies Stripe's answer.

What to ask for

The builder adds payments only when you ask. A shop that records orders, a plans page that records requests, a booking page that holds a slot: each of those takes no money and says so, until you say otherwise. When an app looks like it could take money, the builder offers it as a chip, and tapping the chip is the ask.

One-time charges. Say checkout, deposit, dues, sell tickets, pay by card, or charge:

  • a booking page that takes a $50 deposit to hold a time for my photo sessions
  • sell $15 tickets to our chili cook-off, 80 seats, with a list of who's coming
  • a members page where everyone pays their $40 annual dues for our running club
  • a shop with checkout for my candles
  • a tip jar with a live total for my Saturday street set

Something that recurs but that you collect yourself each time, like annual dues or a season pass, is still a one-time charge: one order per period, and the roster shows "paid through".

Paid memberships. Say paid membership, subscribe, a month, yearly, membership fee, or members-only:

  • a paid newsletter where readers subscribe for $5 a month to read the members-only posts
  • a members-only recipe club with a monthly membership for my sourdough recipes
  • a $20/month coaching community where paying members see the weekly video

A membership is a subscription Stripe renews and retries on its own. The app mirrors what Stripe says about it: active members are in, a member whose card bounced gets a few days of grace while Stripe retries, and a cancelled membership runs to the end of the period the member paid for. Members cancel or change their card on Stripe's own page, reached from a button in your app.

Put the price and the period in the ask. $5 a month tells the builder you want a membership; $40 dues tells it you want one charge. Prices live in your app's code, so you change them by asking for a change, and a buyer can never send their own amount.

What you set up once

  1. Open the Stripe dashboard and sign in, or create a Stripe account. Turn on Test mode until the app is working.
  2. Go to Developers → API keys and reveal the Secret key. Set it on your vibe as STRIPE_SECRET_KEY: the app's Settings page, or npx vibes-diy secrets set STRIPE_SECRET_KEY --vibe you/your-app.
  3. For a membership app, also go to Settings → Billing → Customer portal and save it with Cancel at end of billing period on. That is the page your members use to cancel or change a card, and it exists once you save it.
  4. To go live, repeat steps 2 and 3 with Test mode off. Records made in test mode belong to test mode: a test order or membership points at test payments that the live key cannot read. Before you set the live key, clear the test records from the app's Data tab (or build and test on a copy of the app), so no tester keeps access and no real member is told they already have a membership.

Until the key is set, the app shows you these steps in its own words, and everyone else sees a calm "payments are not open yet". The moment the key lands, the Pay buttons work, with no redeploy. In test mode, the card 4242 4242 4242 4242 with any future date pays.

How it works, in one paragraph

Your app's backend writes the order (or the membership record) first, in a pending state, then asks Stripe for a Checkout Session for exactly that record and hands the page its URL. The page opens the URL in a new tab, because a vibe runs inside a frame that cannot steer the page around it. When the buyer returns, the backend reads the session back from Stripe, checks it belongs to this record at this amount, and only then marks it paid. For memberships the backend also reads the subscription back on a schedule, so a failed renewal or a cancellation reaches your app without a webhook. The rules in access.js make it structural: only your backend can change an order's state, and for a membership the members-only channel is a grant the membership record carries and the backend withdraws.

Where the edges are

  • One Stripe account per app. Every buyer pays you. An app where each visitor collects money into their own account is a marketplace, which needs Stripe Connect and is not what a vibe builds today.
  • Buyers sign in. An order is a record between a person and you, so the buyer has a Vibes DIY sign-in. A visitor who is not signed in sees a "Sign in to join" button, not a broken one.
  • Apple Pay and Google Pay work on Stripe's page, where the card form is. They are not available inside the app's own frame.
  • Memberships follow Stripe's status, and only that. The app reads a subscription's status, its period and whether it is set to cancel. A refund, a discount or pausing collection in the Stripe dashboard changes none of those on its own, so access stays as it was. To end someone's access, cancel their subscription in Stripe; the next read picks that up.
  • Stripe's fees apply, and Stripe Billing adds a small percentage on subscriptions. Your dashboard shows the exact numbers for your account.

Related