Tour Dash
Report · 4 September 2026

Stripe Connect Wired In

Phase 1 shipped a wallet with nothing behind it. A balance was a sum of rows any user could insert for themselves, and pressing Withdraw wrote a negative row and said it was being processed. That is now a real marketplace: the agent's card is charged, Tour Dash holds the money, and the provider is paid when the showing is confirmed done. We take 20% on a single house showing, less as the service gets more expensive.

Scope Payments, payouts and the fee Status Deployed; blocked on Stripe account verification
01

How a booking now works

The sequence is the design. Paying is what books the applicant, rather than something that happens after.

StepWhat happens
Provider signs upBefore anyone can book them they connect a bank account through Stripe Express. Stripe collects the identity and banking details on its own pages and runs the checks. Tour Dash stores the account id and three booleans, never an SSN or an account number.
Agent picks an applicantThe button says Book and pay $50 rather than Approve, so the amount is named before a card is touched. If the provider has not finished payout setup the booking is refused outright, because the money would arrive with no lawful way out.
Agent paysStripe Checkout takes the card. Nothing in the app has changed yet.
Stripe confirmsOnly now does the webhook approve the application, create the appointment and mark the listing filled. Approving first would let a declined card leave a listing locked to a provider who never gets paid.
Showing happensThe money sits with the platform in between. That is deliberate: while it is held there is something to refund if the showing falls over.
Agent confirms it happenedMark complete and pay transfers the provider their share. Stripe pays it out to their bank from there.

The status dropdown no longer offers "Completed". It used to, and setting it did nothing but change a label, which after this change would have stranded the provider's money. There is now exactly one route to a completed listing and it is the one that pays.

02

The fee

The Settings page used to promise a 5% platform fee. That was placeholder copy from the build rather than a decision, and 5% of a $50 showing is $2.50, which does not cover the card processing on the transaction. The rate is now anchored where the volume is: 20% on a single house showing. The rule underneath is $5 plus 10% of the price, which is exactly 20% on the ordinary $50 job and slides down from there.

ServiceWe keepProvider getsOur rateShowami keeps
$45$9.50$35.5021.1%$17.00 · 37.8%
$50 — single house showing$10.00$40.0020.0%$18.00 · 36.0%
$100$15.00$85.0015.0%$21.00 · 21.0%
$200$25.00$175.0012.5%$25.00 · 12.5%
$400$45.00$355.0011.2%$33.00 · 8.2%

Part of the fee is flat, so the rate falls as the service gets more expensive, from 30% on the $25 floor to about 11% on a $400 job. That taper is the point: a $400 job is not eight times the work of a $50 showing, and a flat percentage would be heaviest exactly where two licensed agents find it easiest to settle up off the platform.

Against Showami we are well under on the ordinary showings that carry the volume, $10.00 against their $18.00 at the median, level with them around $200, and above them at the very top of their range. That is a deliberate trade rather than an oversight, and it is the number to revisit first if high-value jobs start leaving the platform.

One detail worth recording because it was nearly a bug. An earlier draft capped the fee at a flat $50, and processing on a $2,000 service is $58.30, so the cap would have meant paying $8.30 for the privilege of running the booking. The cap now cannot push the fee below processing plus a margin, and it sits high enough ($150, binding around $1,450) to be a safety rail against a mistyped price rather than a pricing lever.

03

What stops it going wrong

Three things, each guarding a specific way a marketplace loses money.

GuardWhat it prevents
Clients cannot write moneyThe policy letting a user insert their own transactions is dropped. While the balance was decorative that was harmless; the moment a balance can be paid out it is a way to mint money. The webhook is now the only writer, and every table holding money is readable by the two people involved and writable by nobody.
Every event handled onceStripe retries a webhook until it gets a success, and says plainly that an event can arrive twice even after one. Each event id is recorded before the work is done, so a retry cannot pay a provider a second time. The transfer itself also carries an idempotency key.
One copy of the feeThe fee is computed in the browser, to tell the agent what they will pay, and in the Edge Function, to tell Stripe what to take. Two hand-maintained copies is how a marketplace quotes one number and charges another, so the build now generates the second from the first and fails if they drift.
04

Where it stands

The database is already live. The application code is committed. The functions that actually talk to Stripe are written but not deployed, so nothing can take a payment yet.

PieceStatusDetail
DatabaseLivepayments and stripe_events tables, Connect columns on profiles, the tightened transaction policy. Applied and verified.
Stripe keysStoredPublishable key in the app environment. Secret key held outside the repository and loaded into Supabase secrets, never compiled into the browser bundle.
App codeCommittedTypechecks and builds. Payout setup, the pay-to-book flow, mark-complete-and-pay, the honest wallet, the real fee table.
Edge FunctionsLiveAll five deployed and answering. Verified against the deployed bundle rather than the local file: a $50 showing returns a $10.00 fee in production.
Webhook endpointsLiveTwo of them. Events about our own account (a checkout completing, a refund) sign with one secret; account.updated for a provider's connected account is only ever delivered to a Connect endpoint, which signs with another. Same URL, same handler, both secrets tried.
Platform payoutsBlocked at StripeThe Tour Dash account reports payouts_enabled as false. Charges work; money cannot leave until Stripe's remaining account requirements are satisfied in the dashboard.

One thing still needs a person rather than more code: the platform account reports payouts_enabled: false, and a provider cannot be paid out of an account that cannot itself pay out. That is finished in the Stripe dashboard, not here.

After that, walk one real booking end to end before letting this near a median showing. The $25 minimum exists partly so that first test costs $25 rather than $50.