Let the buyer choose who converts, and the collaborator agree to their split
Three things the settlement-currency work left owing: the buyer had no say
in how a cross-currency purchase was converted, the docs still said
USD-only, and a creator could be given a revenue share in a currency they
do not hold without ever being asked.
THE BUYER'S CHOICE. A radio pair on the cart and a checkbox on the
cross-seller bar, stored as a preference so a returning buyer is not asked
twice, and carried in the session so a chained multi-seller run keeps the
choice it started with. An unparseable form value reads as convert-at-
checkout: a mangled value must not silently drop someone onto the path
where the cost is invisible until their statement arrives.
The task specified showing this only when the buyer's currency differs
from the seller's. That is not knowable. There is no geo, locale or IP
signal in the codebase, and settlement_currency defaults to USD for every
account, so it is evidence of a buyer's currency only once they have
connected Stripe; treating the default as fact would hide the control from
exactly the UK fan who needs it. So it hides only on positive knowledge of
a match and is worded conditionally otherwise.
WHAT CAN HONESTLY BE SHOWN. Before payment, the published 2-4% range and
the fact that Stripe displays the exact converted total on its own page.
After payment, the exact figure: migration 193 stores what Stripe actually
charged, read from presentment_details on the completed webhook, and the
receipt renders it. Both columns or neither, by CHECK. The presentment
currency is deliberately unconstrained, unlike the six we settle in --
Stripe presents in 150+ markets and this column records what happened
rather than what we chose.
THE SPLIT HAS TO BE ACCEPTED. Migration 194 makes a membership pending
until the collaborator agrees. Pending reserves the percentage, so an owner
cannot promise the same revenue twice, but earns nothing: a share starts at
acceptance and is not backdated, because accruing money for someone who may
yet decline invents a debt that is worse to unwind than never to have made.
Declining frees the percentage. Existing members are backdated to added_at,
since being added was the agreement under the old rules and leaving them
pending would have switched off every live split.
That gate is what gives the currency disclosure somewhere to live. The
collaborator sees, before agreeing, that their share arrives in the
project's currency and that Stripe converts it at their payout out of their
share; the owner sees the same when they invite. Neither could be told
earlier, because there was no earlier.
Found on the way: create_transaction_splits and create_tip_splits never
wrote the currency column migration 190 added, so every new split would
have taken the 'usd' default whatever the sale was in.
Also fixed, all the same class of silent USD: item.html published
priceCurrency "USD" in JSON-LD, which machines read and would misprice a
non-USD creator's work in search results; the fee breakdown quoted US card
pricing at everyone, and is now shown only where it is true; the disclaimer
invented a $15 chargeback fee, replaced by a pointer to Stripe's own
pricing for the reader's country; and the payments tab tested
splits_outgoing_total != "$0.00" as a zero check.
The per-seller analytics time-series still sums a creator whose settlement
currency changed. Documented at the query rather than papered over:
splitting a chart per currency is a chart-design decision, not a query fix.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-06 23:56 UTC