12 — API Mapping (Payments)
- E1 — Process payment (S3)
- E2 — Refund (S4)
- E3 — Reconcile (S5)
- E4/E7 — Lists (S1/S7)
- E5/E8 — Detail
- Realtime
- Caching & offline
Exact endpoints from
payments.controller.ts, mapped to screens. Wire contract from 00-shared/07 — note the pagination deviation below.
Base: /api/v1 · Auth: JwtAuthGuard (RBAC perms (planned)).
| # | Method | Path | Screen | Notes |
|---|---|---|---|---|
| E1 | POST | /payments | S3 record | body ProcessPaymentDto; returns {payment, receipt}; emits PaymentProcessed |
| E2 | POST | /payments/refund | S4 | body RefundPaymentDto; 409 rules |
| E3 | PATCH | /payments/:transactionRef/reconcile | S5 | body {status:string} |
| E4 | GET | /payments?page&limit | S1 | returns {data, total} — no shared meta |
| E5 | GET | /payments/:id | S2 | 404 if missing |
| E6 | GET | /payments/invoice/:invoiceId | S8 | array (unpaginated) |
| E7 | GET | /payments/receipts?page&limit | S7 | {data, total} |
| E8 | GET | /payments/receipts/:id | S6 | 404 if missing |
E1 — Process payment (S3)
- Request:
{ "amount": 250, "currency": "USD", "gateway": "cash",
"gatewayTransactionId": "G-123", "invoiceId": "…", "payerName": "A. Kumar",
"payerEmail": "a@x.com", "description": "Term 1 fee" }
- Response (data):
{ payment: {transactionReference, amount, fee, refundedAmount, currency, gateway, status:"completed", invoiceId, payerName, payerEmail, createdAt}, receipt: {receiptNumber, paymentId, amount, fee, currency, paymentMethod, payerName, issuedAt} } - Loading: submit spinner → success screen. Caching: none (write).
- Optimistic UI: none — server-confirmed only.
- Errors: 400 validation (field
details), 409 duplicates, 5xx. - Idempotency:
transactionReferenceauto-generated server-side; no client Idempotency-Key (OQ-3).
E2 — Refund (S4)
- Request:
{paymentId, amount?, reason?} - Rules (service
payments.service.ts): status must becompleted(409); refund total ≤ amount (409); full →refunded, partial →partially_refunded. - Response: updated payment doc.
E3 — Reconcile (S5)
- Request:
PATCH /payments/{transactionRef}/reconcilebody{status}—"success"→ completed,"failed"→ failed, anything else → pending. - Response: updated payment.
E4/E7 — Lists (S1/S7)
- Query:
page(default 1),limit(default 20). - Response shape deviation:
{data:[…], total}— the shared envelope addsmetaonly for{data, meta}payloads (response-envelope.interceptor.ts:25-32), so the client must derive pagination fromdata.length+total. Documented as OQ-2 (inconsistent withPaginationMetaelsewhere). - Sort: server-fixed
createdAt/issuedAtdesc;sort/qparams not supported.
E5/E8 — Detail
- Returns single doc; 404 →
RESOURCE_NOT_FOUND.
Realtime
PaymentProcessed/PaymentRefundedevents →WsBridgebroadcasts totenant:{tenantId}room (ws-bridge.service.ts) → client can live-append list / refresh invoice dues. Not routed to BullMQ (event-queue-map.tshasPaymentCompleted→emails dead entry;PaymentProcessedhas no entry).
Caching & offline
- Lists: client cache 5 min (stale-while-revalidate); detail 1 min.
- Offline: read-only cached views + banner; writes blocked (no offline payment queue — money path never optimistic).