A marketplace for paid conversations has to decide, in advance, exactly which money it owns and which it merely routes. Get it wrong in either direction and the failure is structural: hold the whole payment and you have become the seller, with the tax and liability surface that implies; hold none of it and you cannot enforce a refund when a conversation never happens. The boundary the Elders marketplace drew is narrow on purpose (the platform takes a fixed application fee and the rest of each payment goes straight to the person who answered, through Stripe Connect), and every rule in the product exists to keep that line from blurring.
The product is a paid-chat marketplace: an asker pays a daily subscription to message an askee. It is currently in Stripe test mode, because the production business, Stripe Identity, Connect, and payout requirements have to be activated and audited before real money moves. The boundary is drawn first, and live charges follow the audit, not the other way around.
the line between asker and askee
The role model is the first boundary. Every user begins as an asker; becoming an askee adds a public discovery profile, Stripe recipient onboarding, and a chat inbox to the same account. Role is a capability, not an account type: one account can hold both, and the product is explicit that a user’s home route is a preference, never an authorization decision. That matters for the payout boundary because it means “is this an askee” is a state check on the account’s recipient capability, not a claim about who the user is. The same account can be both, and the capability is what gates each side.
The payment shape is fixed and public: one platform-owned Stripe Price representing $50 USD per day, a $5 platform fee expressed as application_fee_percent: 10 on subscription data, and the remainder transferred to the askee’s connected account as a destination charge. The platform’s take is a percent applied by Stripe at charge time, not a wallet the platform holds and later pays out. The money never lands in a platform balance waiting to be disbursed.
what the platform owns
The platform owns the product, not the payout. Concretely, that means it owns the public askee profiles, the discovery index, the conversations, the product policy, and the provider state (the projection of Stripe objects into local records). It owns the Checkout session creation, the subscription projection, the refund and dispute posture, and the entitlement that unlocks a conversation. It does not own the askee’s funds; under destination charges the platform owns refunds and disputes as a matter of policy, but the proceeds themselves route to the connected account.
The Stripe side of that split is explicit in the account model: an asker gets the customer configuration so the account can pay; an askee gets the recipient configuration with Stripe Transfers and the Express dashboard for payout management. Payout setup binds to a live Accounts userinfo read (the connected account is created against the verified identity, not a form field) and the account link is single-use with an exact same-origin return, so a leaked or replayed onboarding URL cannot attach a different recipient.
Every provider read carries a local projection revision, and a provider response that is superseded (say, a subscription state that has since been refunded, disputed, or reversed) cannot restore access. The local record is not a cache of the provider’s state; it is a projection with fencing, so stale evidence does not get a second chance to be true. The same revision discipline is what the credits ledger in a sibling lesson uses to keep provider replays from double-spending.
what it never touches
The rule that keeps the platform honest is that the browser is never authority for payout. Before a Checkout is created, the application retrieves the canonical connected account and rechecks the recipient configuration and transfer capability. A return URL, a client-supplied field, or a cached capability label is never treated as proof that the askee can be paid. An askee can be browsed before payout onboarding is complete, but the Start chat affordance stays disabled until the recipient’s transfer capability is active.
The same posture applies to identity. Becoming an askee involves Stripe Identity verification and Connect onboarding through single-use Account Links on an Express dashboard, and a return redirect from those flows is never authority for the badge or the payout state. The canonical account is re-read and the exact capability is checked. An askee’s email is sent to Stripe as the account contact only after a disclosed action; it is not stored in the product’s own database and it is not returned to the browser. A dual-role user sees Browse and Inbox as preferences; the ability to receive money is gated on the provider’s current record, not on a role flag that could be stale.
The discovery surface keeps the same boundary. The public askee projection contains the fields a visitor needs (username, age range, bio, topics, accomplishments, payout readiness) and omits every private or provider field by construction, so a profile can be searched and browsed without exposing the account’s Stripe state. A public askee is included in the sitemap only when the profile is visible and safe to discover; the account, chat, settings, checkout, and API routes are all noindex.
the entitlement is the gate
Access to a conversation is an entitlement derived from a webhook-reconciled subscription, not from the checkout return. Only a current, provider-verified subscription unlocks the chat between an asker and an askee, and the invariant is structural: at most one conversation and one current subscription exist per asker–askee pair, enforced as a uniqueness constraint, so a duplicate subscription cannot be created to double-unlock a conversation or double-bill an asker.
Message writes are entitlement-gated and idempotent: a send is keyed by (conversation, sender, clientRequestKey) so a retried request cannot post twice, and only the current paid asker and the askee can send while the entitlement is active. The product’s transaction boundaries keep the conversation and its entitlement consistent: the subscription, the conversation, and the next message sequence are reconciled together, not in separate writes that could drift. The subscription itself is gated the same way on the other side: Checkout creation is idempotent and binds the requester, the recipient, the Price, the environment, and the request version, so a retry reopens the same checkout rather than starting a second subscription for the same pair.
the adverse cases are designed
The boundary is honest about the ways money reverses. Refunds, disputes, transfer reversals, payout failure, cancellation timing, and platform liability are visible operator states before live mode: they are modeled, not discovered in production. A refund or a lost dispute reverses access; a superseding provider state cannot quietly restore it. The platform owns that posture precisely because it is the one charging the fee: the party that keeps $5 of the $50 is the party that can unilaterally issue a refund, and the product makes that authority explicit in code rather than implied in terms of service.
This is also why the product stays in Stripe test mode until the production requirements are activated and audited. The boundary is a legal and financial claim, not only a technical one (who is the merchant of record, who can refund, who carries the dispute), and the code does not get to decide that unilaterally.
The deliberate separation is the whole lesson. The platform owns the marketplace: who can be found, who can talk to whom, what a conversation costs, and what happens when it goes wrong. It never owns the proceeds, because the proceeds belong to the askee and Stripe Connect moves them directly. Keeping those two things distinct is what lets the product be a marketplace instead of a store, and it is also what keeps the platform honest, because the money it can touch and the money it cannot are decided by the charge structure, not by a promise in the terms of service.
sources
- Elders (elders.hraness.com): the asker/askee capability model, Stripe Connect payout boundary, and webhook-reconciled entitlement described here.
- The monorepo behind this site (projects): the Elders product plan and Sup’s credit/checkout state machines that share the same fail-closed posture.
- Stripe Connect and destination charges: the provider mechanics behind
application_fee_percentand direct transfer.