Self-service

Refunds without WhatsApp threads.
Attendees do it themselves against your policy.

Set the refund policy per event — full refund up to N days before, partial % up to M days before, none after. The confirmation email carries a "Manage booking" link. Attendees see their eligible amount computed live, submit a request, done. Admin approves in the refunds queue. Zero support inbox, zero back-and-forth.

Attendee · Manage
Priya Nair
Seat V-7 · Product Summit 2026
Refund policy
• Full refund up to 7 days before
• 50% refund up to 1 day before
• No refund after
Full refund of ₹5,000
Event is 12 days away, within the full-refund window.
Request refund of ₹5,000

A policy that fits any event.

One JSON blob per event. Defaults are 7 / 1 / 50, override per event.

📅
full_refund_days
If the request lands earlier than this many days before the event, attendee gets 100% back. Default 7.
🕒
partial_refund_days
Between full and this, attendee gets the partial %. After this, no refund. Default 1.
💯
partial_percent
The percentage refunded in the partial window. Default 50. Set to 0 to have "full or nothing".

The whole flow, no organiser involvement.

1
Attendee taps "Manage booking"
The link is in their confirmation email — /manage/{qrToken}. Opens on any device, no login, signed by the QR token.
2
See eligibility live
Policy explained in plain English. Eligible amount computed from days-to-event × policy. "Full refund of ₹5,000 available" or "Only ₹2,500 refund available".
3
One-line reason, submit
Attendee optionally adds a note ("work conflict", "flying out"). Request created with status=pending. Duplicate guard blocks multiple pending refunds on the same order.
4
Admin approves in queue
Refunds queue shows all pending. One click to approve, which fires the Razorpay refund API. Attendee gets the money back to the same card / UPI.

The edge cases that eat support hours.

🚫
Already refunded
If a refund is pending / processing / succeeded, the button hides. The old "hey can you check my refund status" ticket disappears.
📆
Event already happened
Days-to-event goes negative → policy explains why no refund is available. Attendee never files a request that would be rejected.
🎁
Free registration
Zero-total orders hide the refund button — there's nothing to refund. Attendee sees "This is a free registration, nothing to refund."
🔒
Off by default
self_service_refund_enabled defaults to false. Organiser opts in per event. High-stakes events keep the manual approval loop.
📜
Audit-logged
Every refund request records who (attendee email), what (amount), when. Feeds the Audit Log feature — refund.requested rows searchable by admin.
🔗
Waitlist auto-fills the seat
When admin approves the refund, the OrderService cancel path triggers WaitlistService.promoteNext. Cancelled seat auto-invites the next waitlist entry within seconds.

Because "refund me pls" turns into 40 WhatsApps in 12 hours.

Any paid event that sells more than 200 tickets will get a refund cluster in the final week. Attendee falls sick, work meeting shifts, kid has a school event, mother-in-law flies in. On our biggest ticket volume client, the pattern was clear: 40 refund WhatsApps between Thursday and Sunday for a Monday event. Each one required checking the payment, computing the refund amount against a policy that lived in someone's head, initiating the refund on Razorpay dashboard, replying with confirmation. 40 conversations × ~10 minutes each = the ops person's entire Friday.

Half those conversations were also arguments: "your policy said 50%, why am I only getting 40%?" — because someone had computed with the wrong days-to-event. The audit trail was a WhatsApp thread. Chargebacks followed.

So we made the policy a JSON blob on the event. The days-to-event computation happens server-side. The attendee sees the eligible amount before they even click submit — no argument possible. The refund lands in the refunds queue with a full audit trail. Admin approves in one click. Razorpay refund API fires. Attendee gets an email confirmation.

The ops person got their Friday back. Chargebacks went to zero because attendees stopped feeling ambushed by the number.

Where the flow shows up.

Approved refund → OrderService cancels → waitlist auto-invites the next entry. Cancelled seats never sit empty.
📜
Every refund request logs a refund.requested row — attendee, amount, order. Compliance-ready trail.
🧾
Reuses the Razorpay refund API that ticketing already has wired up. No extra gateway integration needed.

Questions we get

Is auto-refund on by default?
No. self_service_refund_enabled defaults to false per event. Organiser opts in explicitly. If you never toggle it on, attendees see "contact the organiser" and nothing else.
Does the money go back automatically?
The attendee's request creates a pending Refund row. Admin approves in the refunds queue, which fires the Razorpay refund API. So: attendee-initiated, admin-approved, gateway-processed.
Can I set different policies per tier?
Not yet — one policy per event. Per-tier policies are on the roadmap; ask us if you need them.
What about reschedule to a different event?
Reschedule is on the roadmap as a next iteration. Today the flow is refund → attendee re-registers for the new date. When reschedule ships it will preserve the seat number and roll into the new event.
What if the attendee already checked in?
The checked-in flag shows on the manage page. Refund is still policy-allowed based on days-to-event, but admins get a clear signal during approval.
Stop replying to refund WhatsApps at 10pm on Sunday.
See the self-service flow with a live policy in 8 minutes.