Billing
Issuing refunds
How team and club staff issue full or partial refunds against Stripe payments, what the household sees, and how refunds flow through the books.
- Platform:
- both
- Audience:
- staff, club_admin
- Last reviewed:
- 2026-05-21
Who can issue a refund
Refunds are tied to whoever can create / manage payments on the team or club, since refunding a payment is part of running the payment event.
- Team payments — staff whose position is Manager, or staff with no position assigned (existing setups stay unrestricted).
- Club payments and club registrations — club admins; staff whose position is Club Admin, Registrar, or Finance; or staff with no position assigned.
Positions like Team Coach / Assistant Coach / Physio, Team Other, and Club Director can see payments but cannot issue refunds — they're managed by whoever owns billing operations on your team or club. See Staff roles and permissions for the full breakdown.
Households cannot trigger refunds themselves. If a family asks for one, they're asking the team or club; you decide whether to issue it.
When refunds are available
The Refund action shows up next to a recipient as long as all of these are true:
- The payment went through Stripe (the recipient has
paid_via = stripe). Manually marked-paid recipients can't be refunded in-app — handle those off-platform. - The recipient has at least some refundable balance:
amount_paid_cents − refunded_cents > 0. - Your team or club subscription is active.
Fully refunded recipients hide the Refund icon and show a Refunded pill instead.
Where the refund button lives
Web
- Team payments: open the event from Team → Payments → [event]. Each recipient row has icon-only actions on the right: copy pay link, send reminder, mark paid, and refund (curved arrow). Click the refund icon to open the drawer.
- Club payments: same pattern at Club → Payments → [event].
- Club registrations: open the event at Club → Registrations → [event], open a submission row, then tap Refund in the submission drawer (next to Send reminder).
Mobile
- Team payments: Payments → [event] → tap the Refund action on the recipient card.
- Club payments: Club → Payments → [event] → tap Refund on the recipient card.
- Club registrations: open the submission detail sheet from the staff registration screen, then tap Refund.
What the drawer asks for
The refund drawer shows three summary chips (Paid, Refunded, Refundable) followed by:
- Amount — defaults to the remaining refundable balance. Edit to issue a partial refund.
- Reason (optional) — a Stripe enum: Customer requested, Duplicate charge, Fraudulent, or No reason. Carried through to Stripe.
- Internal note (optional) — staff-only free text, up to 280 characters. Saved with the refund row for audit; not shown to the household.
If the recipient has prior refunds, a Refund history list appears above the form with each entry's date, actor, status, reason, and note.
What the household sees
After a successful refund the household-facing surfaces all update automatically:
- The public pay / receipt page (the link they paid through) shows:
- A Refunded chip when fully refunded, or Paid · partial refund / Partial · refund when partial.
- The "$X paid of $Y" line gains "· $R refunded".
- A new Refunds section listing each refund with date + amount.
- The Pay button reappears once a refund reopens the obligation — fully refunded → the full amount is due again; partially refunded → the remaining balance is due — so the household can re-pay with the same link.
- The Stripe-issued receipt remains on file with the household; the refund posts to the original payment method (5–10 business days for cards, longer for ACH).
- The "Email me a copy" button on the pay page now emails a receipt that includes the refunds subsection.
- A transactional email + push notification fires when the refund succeeds: the household sees "Refund issued — $X.XX" on the payments notification channel.
What staff sees in dashboards after a refund
Refunds are accounted for net of the original payment everywhere money is summed:
- Team Payments Overview tab — "Total gained" + per-event progress bars drop by the refund amount.
- Event detail Finance card — "Collected" total reflects net.
- Club Money Collected chart (Club home / dashboard) — bar for that day or month shrinks.
- Club Financials Hero, Collected-over-time chart, Top earning events, By team, Top households — all net of refunds for the visible range.
- The Recent Activity card on Club Financials adds a Refunded status row when a recipient is fully refunded.
- The recipient's row reads Refunded (gray) or Paid · partial refund depending on state.
When a refund succeeds, the recipient's obligation status is re-derived from net paid (amount_paid_cents − refunded_cents): fully refunded → pending, partially refunded below the obligation → partial, still covered → paid. Reopening lets the household re-pay with the same pay link / lookup token (free club registrations — not_required / $0 — are left unchanged). The refunded_cents counter still tracks lifetime refunds separately, so dashboards report money collected net of refunds.
Refunds initiated in Stripe Dashboard
Staff with Stripe Dashboard access can issue a refund directly there as well. Athleit's webhook listens for charge.refunded / refund.created / refund.updated and writes the same audit row with source = "Stripe Dashboard" (no in-app actor). The household-facing receipts and staff totals update the same way — out-of-band refunds and in-app refunds are equivalent on the Athleit side.
Refund history (audit) for records
Every refund row keeps a permanent record. From the staff refund drawer, the Refund history list shows for each refund:
- Date + time (local)
- Actor — staff member's name for in-app refunds, "Stripe Dashboard" for out-of-band ones
- Amount + currency
- Status pill — Succeeded (green), Pending (yellow, ACH still settling), Failed (red), Canceled (gray), Action required
- Reason chip (when set) and free-text note (when entered)
- Stripe refund id (under the hood) for reconciliation
Refund rows are immutable — there is no edit or delete UI, and the database refuses hard-deletes by trigger. To "undo" a refund you'd issue a fresh charge.
What the Athleit platform fee does on refund
When a household paid an Athleit service fee (the per-checkout fee your platform may pass through), that fee stays with Athleit; only the principal returns to the household. Stripe's payment processing fee (typically ~2.9% + $0.30 on cards, ~0.8% capped at $5 on ACH) is also kept by Stripe. The connected account's balance funds the refund.
In practice this means: refunding a $100 charge returns $100 to the family; the team / club balance is debited by $100; the Athleit service fee + Stripe processing fee originally paid on that charge are not recovered.
What this doc cannot do
- Refund manual payments — those weren't a Stripe charge to begin with. Handle off-platform.
- Refund individual installments by index. The refund drawer targets the most recent successful charge on the recipient; if you need to refund a specific historical installment, do that in Stripe Dashboard (it'll sync back the same way).
- Refund the platform fee — that's a product decision and not exposed.