Refunds & Cancellations
A cancellation costs the property a sale and the guest some money. Both deserve a fast, predictable, well-communicated process — no "we'll call you in 3 days". The refund engine evaluates the property's policy, computes a number, and runs it through Razorpay (or records cash) automatically.
What triggers a refund
Guest cancellation
From their account page, or by writing to support, or asking at the desk.
Property cancellation
Owner cancels (over-booking, force majeure, room damage). Full refund + apology email mandated.
No-show
Guest never arrived. Per policy: usually one-night charge held, the rest refunded.
Balance default
Partial-payment booking, balance never paid. Advance refund computed per policy.
System over-booking
OTA race made us oversold. Full refund + guest re-accommodated (separate flow).
Chargeback
Razorpay alerts a dispute. Booking auto-locked; finance gathers evidence.
Policy → refund amount, step by step
Identify the policy
The booking carries a snapshot of the property's cancellation policy at the time of booking — policies change, but each booking is locked to the policy that applied when it was made.
Compute hours until check-in
Use the property's local time zone.
Look up refund tier
For Flexible: ≥24 h → 100 %, <24 h → 50 %, after check-in → 0 %.
Apply override
Owner or manager can override (up or down) with a written reason. Audit-logged.
Compute taxes
Refund proportionally cancels GST & city tax. Razorpay receipt is reissued.
Execute refund
Per original payment method.
Refund per payment method
| Original method | Refund path | Settlement time |
|---|---|---|
| Razorpay (card / UPI / netbanking / wallet) | Razorpay refund API → original method | 3–7 working days |
| UPI (manual ref) | Property sends UPI from registered hotel ID. Agent records the new transaction ID. | Same day |
| Cash | Cash refunded at desk. Numbered debit receipt issued. | Immediate |
| Bank transfer / NEFT | Property initiates NEFT. Records UTR. | 1–2 working days |
| OTA-collected | Cancellation pushed to OTA; OTA refunds the guest per their policy. ABc records, doesn't process. | OTA-dependent |
Cancellation UI — guest view
Refund computation — worked examples
| Policy | Time before check-in | Paid | Refund |
|---|---|---|---|
| Flexible | 5 days | ₹22,230 | ₹22,230 (100 %) |
| Flexible | 8 hours | ₹22,230 | ₹11,115 (50 %) |
| Moderate | 3 days | ₹22,230 | ₹11,115 (50 %) |
| Strict | 3 days | ₹22,230 | ₹0 (0 %) |
| Non-refundable | 10 days | ₹22,230 | ₹0 |
| Property-cancels | any | ₹22,230 | ₹22,230 (100 %) + apology credit ₹500 |
Refund API — server side
// Request { "amount": 22230, // optional — defaults to remaining refundable "reason": "guest_cancellation", "notes": "Travel plans changed; flexible policy, 5 days out, 100 %", "idempotency_key": "refund_bk_…_1" } // Server flow: // 1. Check booking state + policy // 2. Compute max refundable (avoid double refunds) // 3. If original was Razorpay → razorpay.payments.refund(paymentId, {...}) // If original was cash → create debit payment row, mark for desk handout // 4. Update booking → cancelled // 5. Push availability release to OTAs // 6. Email guest + email owner // Response — 201 { "refund_id": "rfd_…", "amount": 22230, "method": "razorpay", "razorpay_refund_id": "rfnd_M…", "status": "processing", "eta": "3-7 working days" }
Owner / manager override
Sometimes the system says "50 %" but the property wants to make a goodwill gesture (or vice versa, a strict policy needs to hold).
The override modal forces a reason and a manager-or-higher role. Both the system-computed amount and the override amount are stored — finance can see exactly how often overrides happen and by whom.
Refund status tracking
| Status | Meaning |
|---|---|
| initiated | API called, awaiting gateway confirmation |
| processing | Razorpay accepted, settling to bank/card |
| completed | Guest received the money (webhook confirmed) |
| failed | Razorpay returned an error; manual intervention required |
| manual_pending | Cash / NEFT refund waiting for desk to hand out / send |
Edge cases
- Refund after partial check-in — guest stayed 1 of 3 booked nights and leaves. Refund = total − (1 night × ADR) − pro-rata tax.
- Refund across split payments — paid ₹10k cash + ₹12k card. Refund 22k: card portion via Razorpay, cash portion via desk debit.
- Refund after gateway timeout — initial refund call to Razorpay times out. We retry with the same idempotency key — no double refund.
- Chargeback while refund in flight — lock the booking; let finance reconcile. Cancel any pending refund to avoid double-out.
Reporting
Owners can see, per month:
- Cancellation rate (% of confirmed bookings cancelled)
- Average refund (₹) per cancelled booking
- Top cancellation reasons
- Net revenue after refunds vs gross bookings