Participants pay
Each participant has their own link:
https://share-pay.co.uk/split/pay/<pay_token>
They open it, see only their share, and authorise a card hold. The page works in any browser. Someone with the SharePay app installed opens the link in the app instead, which shows the same share and then hands off to the same secure card page, so the amount and the outcome are identical either way.
What the payer is charged
Three lines, in this order: their share, a flat 20p SharePay service fee, and the total charged to their card. The hold and the eventual charge are both for that total, and the button they press quotes it, so nobody meets the 20p after the fact. You receive the share. See what SharePay charges.
| Line | On a £40 share |
|---|---|
Your share of <your business name> | £40.00 |
| SharePay service fee | £0.20 |
| Total charged to your card | £40.20 |
A participant whose share was cancelled sees their share alone, because nothing was charged and nothing ever will be.
When every participant has authorised, the engine captures all the holds to your account at once.
There is no decline button
If someone never approves, the group runs out of time and all holds are released. Nobody is charged, including the people who already approved. There is no explicit decline action anywhere in the flow: an unapproved share simply expires.
That means a group that has gone quiet does not produce a fast
checkout_split.canceled webhook. It produces one up to six days later, when
the expiry job reaches it.
Each split is stamped with an authorization_expires_at of creation plus 7
days, matching Stripe's manual-capture window. A job runs every 6 hours and
cancels any split still pending more than 6 days after it was created, so a
hold is always released by us with roughly a day to spare rather than expiring
unpredictably at Stripe's end.
A release we cannot get through to Stripe is the one exception: that hold is
left to lapse at authorization_expires_at on Stripe's own schedule. The share
is still canceled, because nothing was or ever will be captured, and the
customer's copy says they were not charged rather than promising the hold has
already gone.
A share that has already been captured, typically because you took it by
hand in your own Stripe dashboard, is the other exception. It is recorded
captured, not canceled, whether we learn it from Stripe refusing the release
or from the capture webhook arriving first, and we check which case it is rather
than assuming. That person is not sent the "you were not charged" email, and
both the pay page and the app tell them plainly that their share was charged and
quote the real figure, rather than repeating the order's cancellation at them.
It is a charge on a cancelled order, so we alert ourselves to reconcile it with
you.
If Stripe refuses the release and we cannot read the PaymentIntent back at all,
we cannot tell those two apart. Nothing is written to that share, it stays
authorised, that person is told we are still confirming what happened rather
than being given either answer, and we alert ourselves to settle it by hand.
authorization_expires_at is on
GET /api/checkout-splits/:id,
so you can show an exact deadline rather than an estimate. Note the job only
looks at splits whose status is still pending.
Every uncaptured hold on your connected account belongs to a split that is
still collecting approvals. Cancelling any one of them, by hand in Stripe
or with an automated sweep of uncaptured PaymentIntents, cancels the whole
split: the remaining holds are released, the split moves to canceled, every
participant is emailed to say they were not charged, and a
checkout_split.canceled webhook fires. It cannot be undone, and the buyer has
to start again.
To stop a split, use POST /api/checkout-splits/:id/cancel or the SharePay
dashboard. Every SharePay PaymentIntent carries checkout_split_id,
participant_id, order_reference and participant_email in its Stripe
metadata, so you can filter them out of any housekeeping job.
What we email your customers
SharePay sends transactional email directly to the participants, under your business name. This is not optional, is not configurable, and does not use your own from-address. Expect it to arrive alongside your own order emails.
| When | Who gets it | Subject |
|---|---|---|
| The split is created | Every participant except the person who created it | <creator's name> invited you to split <order reference> |
| The split captures | Every participant | Your £<total charged> for <your business name> was charged |
| The split is cancelled or expires | Every participant | Names your business and says they were not charged |
The invite carries the pay link, your business name, the order reference, that person's share, the 20p service fee and the total their card will be charged. The capture email quotes that same total, not the bare share, so it matches their statement. All three are best-effort: a delivery failure is logged and never blocks the payment.
Host the pay step yourself
You do not have to send people to share-pay.co.uk. The pay view behind that
page is a public endpoint, so you can render the payment step in your own
brand:
GET /api/checkout-splits/pay/<pay_token>
No credentials, rate limited to 60 requests a minute per IP. Returns:
| Field | Notes |
|---|---|
merchant_name | Your business name |
order_reference | The order this split is for |
currency | gbp |
amount | This participant's share only, as a decimal string in pounds |
fee | The SharePay service fee on this share, normally 0.20. 0.00 for a participant whose share was cancelled, because nothing was charged |
total | What the card is charged: amount plus fee. 0.00 for a cancelled participant. Quote this, not amount, on any button or confirmation |
split_status | The split's lifecycle status |
participant_status | This participant's own status |
counts | { authorised, total }, for a "3 of 4 approved" indicator |
client_secret | Stripe client secret for placing this hold. null once the participant is no longer pending, because there is nothing left to confirm |
stripe_account_id | The connected account the hold is opened on |
publishable_key | SharePay's Stripe publishable key |
An unknown or dead token returns
404 {"error":"This split link is no longer valid."}.
fee is the figure frozen onto that participant's PaymentIntent when the split
was created, not a live recalculation, so it always agrees with what the card
will actually be charged even if our pricing changes while the hold is open.
client_secret, stripe_account_id and publishable_key are everything
Stripe.js needs to confirm the card on the connected account. The same
clientSecret is also returned per participant by
POST /api/checkout-splits.
A pay token is a bearer credential for one person's share. Treat it as a secret, and never render another participant's token on a page.