Files
baya-monorepo/archive/docs/integration/domains/refunds.md
T
2026-08-02 20:01:31 +03:30

5.5 KiB

refunds — cancellation, reversal, clawbacks, invoices

Client seam client/src/services/refunds/ · USE_REFUNDS_MOCK = true (mock is primary) · 8 server ops Last verified: 2026-07-30 against commit d3ec723 and swagger.v1.json (2026-07-29).

Money going back. The customer half is thin and real; the admin half is largely deferred, which is why the seam is mocked.

Endpoints

Method Path Auth Verdict
GET /api/v1/refunds/by_booking/{bookingId} [Authorize] wired — the customer's refund for a booking
GET /api/v1/refunds/{id}/status [Authorize] wired
GET /api/v1/admin_refunds admin · sensitive wired · paginated
POST /api/v1/admin_refunds admin · sensitive unwired — creates and executes in one call; the client wants preview → approve (REQ-035)
POST /api/v1/admin_refunds/{id}/confirm_settlement admin · sensitive unwired — the manual-channel settlement confirm
POST /api/v1/admin_refunds/{id}/mark_failed admin · sensitive unwired
POST /api/v1/admin_clawbacks/{id}/write_off admin · sensitive unwired — no console screen
POST /api/v1/admin_invoices admin · sensitive unwired — owner-issue an invoice (REQ-018's fallback path)

Also wired by this domain, documented with their owner (bookings.md): POST bookings/{id}/cancel (cancel and refund, REQ-019) and GET bookings/{id}/cancellation_policy (the pre-cancel preview, REQ-020).

Phantom — 4

Client call REQ Note
POST /api/v1/admin_refunds/preview REQ-035 Deferred. Today's single POST admin_refunds creates+executes with no preview step
POST /api/v1/admin_refunds/{id}/approve REQ-035 Deferred
POST /api/v1/admin_refunds/{id}/reject REQ-035 Deferred
GET /api/v1/refunds/my REQ-048 The customer's "all my refunds" list. The wallet «استردادها» tab renders empty on the real path

The money rules

Four, and none of them are the client's to compute:

  1. A refund is a reversal leg, not a deletion. ledger_entries is append-only; every posting group balances. Nothing is ever edited or removed.
  2. Fee-leg decomposition is served, not derived. RefundStatusDto carries platformFeeRefundedIrr and nursePayoutRefundedIrr separately (REQ-021, delivered) — a partial refund does not necessarily refund the commission and the payout in the same proportion. Never split a total.
  3. Pre-payout and post-payout fork. If the nurse has not been paid, the payout leg is simply reduced. If they have, the platform raises a clawback, which the payout engine nets against the nurse's next batch — whole-clawback greedy netting, never a partial. See payouts.md.
  4. VAT is on commission only, so a refund's VAT leg follows the commission leg, never the payout.

Shape rules the JSON does not express

  • refundChannel decides the mechanics and is not a display detail: psp_card reverses through the acquirer, bnpl_revert calls the BNPL provider's revert (see bnpl.md), manual is a bank transfer an admin confirms with confirm_settlement. Each has a different ETA, and expectedCustomerRefundEta is server-computed per channel — the client displays it verbatim.
  • CancellationPolicyPreviewDto is the complete pre-cancel answer (REQ-020, delivered): cancellable, cancellationPolicyCode, refundPercentageApplied, feePercentage, refundAmountIrr, feeAmountIrr, refundableAmountIrr, the two fee legs, appliesTo, leadTimeLabel, refundChannel, expectedCustomerRefundEta, and a per-session breakdown. The client shows it and asks for confirmation; it computes none of it.
  • Cancellation tiers are config rows, not code — cancellation_tier1/2/3_refund_rate in admin.md — and the applied rate is snapshotted onto the refund at compute time, so a later tier change is not retroactive.
  • refundPercentage on CancellationPolicyDto is a rate, refundPercentageApplied on the refund is the snapshot. They can legitimately differ; that is the point.
  • The crash-window fix in refinement-phase-6 wired the previously unreachable BNPL and manual settlement paths — a refund created against those channels now actually clears.

Enums

Vocabulary Values
RefundStatus requested approved processing succeeded failed rejected
RefundChannel psp_card bnpl_revert manual
ClawbackStatus pending recovered written_off
CancellationPolicyCode free_24h partial_under_24h customer_no_show
CancellationLeadTime gt_24h lt_24h started
CancellationScope whole_booking remaining_sessions
CancelReasonCategory (client) changed_mind schedule_conflict found_other_care other

The first three are verified identical to Entities/Refunds/RefundStatus.cs and ClawbackStatus.cs.

Open REQs

REQ Status Effect
REQ-035 deferred No admin preview / approve / reject → 3 phantom routes. The one live route creates and executes together, which the console will not call
REQ-048 open No customer "all my refunds" list → 1 phantom. The wallet tab renders empty on the real path
REQ-033 partially delivered totalIrr is on InvoiceDto; the partner per-booking commission invoice list is deferred. See partner-center.md