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 approve it. That puts a hold on their card: their bank reserves the money, but they are not charged until everyone has approved.
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.
Once every participant has approved, all the holds are turned into real charges together and the money lands in your Stripe account.
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.
A card hold cannot last forever: Stripe gives us 7 days. So every split records
an authorization_expires_at of 7 days after it was created.
We do not let it run that close. A clean-up runs every 6 hours and cancels any order still waiting after 6 days, so we release the holds ourselves with about a day to spare, rather than letting them lapse 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 to release the hold and we then cannot read the payment
back to find out why, we genuinely cannot tell those two cases apart. So we
record nothing, the share stays authorised, and that person is told we are
still confirming what happened rather than being given an answer that might be
wrong. We flag it for a human to settle.
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 sitting on your Stripe account belongs to an order still
waiting on approvals. Cancel any single one of them — by hand, or with a
script that tidies up old uncaptured payments — and you cancel the entire
order. The other holds are released, the order moves to canceled, every
participant is emailed to say they were not charged, and a
checkout_split.canceled webhook fires. None of it can be undone, and your
buyer has to start over.
To stop an order, use the SharePay dashboard or
POST /api/checkout-splits/:id/cancel.
If you do run automated tidy-ups in Stripe, ours are easy to skip: every payment
we create is tagged with checkout_split_id, participant_id,
order_reference and participant_email.
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 | Your Stripe account, which the hold is placed on |
publishable_key | SharePay's public Stripe key, safe to use in a browser |
An unknown or dead token returns
404 {"error":"This split link is no longer valid."}.
fee was recorded when the split was created and is never recalculated. So it
always matches what the card will actually be charged, even if our pricing
changes while the hold is still open.
client_secret, stripe_account_id and publishable_key are everything
Stripe.js needs to take the card on your Stripe account. You get the same
client_secret per participant from
POST /api/checkout-splits.
Anyone holding a pay link can pay that share — there is no password on it. Treat each one as a secret, and never put one participant's link on a page another participant can see.