Payments & Financials API
Payment processing, financial records, and reporting endpoints
1. Purpose
This document defines the REST APIs responsible for:
- Online payments for: Bookings (حجوزات الرحلات), Ad campaigns (الحملات الإعلانية)
- Payment transactions storage and status tracking
- Financial reports exposed to: Super Admin / Finance, Provider companies (payout view)
- Mapping UI financial states: "في الرصيد الحالي", "تم التحويل", "مسترجع"
Important: VAT / tax rules are defined in business-rules-and-policies.md. The discrepancy between 15% (bookings) and 20% (ad campaigns UI) is documented as an open question.
2. Core Financial Entities & Statuses
2.1 PaymentTransaction
Represents a single payment attempt through a gateway (HyperPay / STC Pay / Mada / Apple Pay / SADAD).
Key fields (system level):
idreference — gateway reference / checkout IDuser_id — the operation ownerbooking_id (nullable) — linked booking if payment for a tripad_campaign_id (nullable) — linked ad campaign if payment for adsamount — total amount including VAT (numeric, SAR)currency — "SAR"vat_rate — 0.15 (bookings), 0.20 (ads – pending confirmation)vat_amountpayment_method — credit_card | mada | apple_pay | stc_pay | sadadprovider — hyperpay | stcpaystatus — internal enum
| Enum | Description |
|---|---|
| PENDING | Checkout created, waiting for gateway |
| PAID | Payment successful |
| FAILED | Gateway rejected or error |
| REFUNDED | Fully refunded |
| PARTIAL_REFUND | Partial refund executed |
UI usually shows only "مكتمل" vs "فشل" vs "مسترجع" when needed.
2.2 FinancialRecord (Ledger Line)
Represents a row in التقارير المالية table (رقم المعاملة / المبلغ الإجمالي / عمولة المنصة / المبلغ الصافي / الحالة).
Minimum fields:
idpayment_transaction_idbooking_id (nullable)ad_campaign_id (nullable)gross_amount — المبلغ الإجماليplatform_commission_amount — عمولة المنصةnet_amount — المبلغ الصافي لمزود الخدمةcurrency — SARdetails — text like: "رحلة إلى العلا" / "عمرة رمضان"record_date — التاريخ المعروض في الجدولbalance_status — internal payout status
| UI Label | Enum | Meaning |
|---|---|---|
| في الرصيد الحالي | IN_CURRENT_BALANCE | Amount is accrued, not yet transferred to provider |
| تم التحويل | TRANSFERRED | Amount already paid out to provider |
| مسترجع | REFUNDED | Amount refunded to customer |
4. Booking Payments – Flow & Endpoints
High-level user flow:
- User fills passenger & contact data → POST /api/v1/bookings
- Backend creates Booking with status = PENDING_PAYMENT
- Backend creates PaymentTransaction + gateway checkout
- User is redirected / opens payment widget
- Gateway calls MASARUK webhook + frontend is redirected to success/failure page
- MASARUK confirms payment, updates PaymentTransaction, Booking, and FinancialRecord
4.1 Create Payment Intent for Booking
/api/v1/payments/booking/{booking_id}/intentFrontend SHOULD NOT call this directly in the standard flow; it is triggered by the Booking Service immediately after creating a booking.
4.2 Payment Webhooks (Gateway → MASARUK)
These endpoints are called by payment providers (HyperPay, STC Pay, etc.) after user finishes payment.
- Are unauthenticated but secured via gateway-specific signatures / tokens
- Must be idempotent
/api/v1/payments/webhook/hyperpayBehavior (simplified):
- Resolve PaymentTransaction by checkout_id
- Verify signature and amount
- Map result code to internal status: Success → PAID, Failure → FAILED
- If PAID and transaction not previously processed: Update Booking status → CONFIRMED, Create/update FinancialRecord, Trigger notifications (Email/SMS to user, Dashboard widgets)
- If FAILED, keep booking as PENDING_PAYMENT or mark as PAYMENT_FAILED per policy
Similar webhooks exist for:
POST /api/v1/payments/webhook/stcpayPOST /api/v1/payments/webhook/applepayPOST /api/v1/payments/webhook-sadad4.3 Get Booking Payment Status (Frontend Polling)
Used by Web/Mobile success page to poll while redirect may be delayed.
/api/v1/bookings/{id}/payment-status- If payment_status = PENDING, frontend can show loader
- On PAID, frontend should navigate to final confirmation UI
5. Ad Campaign Payments
For "إدارة الإعلانات" screen, users (Provider or Admin) pay for AdCampaign creation.
5.1 Create Payment Intent for Ad Campaign
/api/v1/payments/ad-campaign/{ad_campaign_id}/intent5.2 Webhook Handling
Same webhook endpoints as bookings; when resolving a PaymentTransaction with ad_campaign_id:
- AdCampaign.status → ACTIVE / SCHEDULED (depending on dates)
- FinancialRecord.details = "حملة إعلانية لرحلة [اسم الرحلة]"
- Card "إجمالي إيرادات الإعلانات" in التقارير المالية is updated
6. Financial Reports API (Admin & Provider)
Matches "التقارير المالية" screen.
Cards:
Table Columns:
6.1.1 Admin – Platform Summary
/api/v1/admin/financial-reports/summary| Parameter | Description |
|---|---|
| period | today | this_week | this_month | custom |
| date_from, date_to | For custom period |
6.1.2 Provider – Company Summary
/api/v1/provider/financial-reports/summaryReturns same structure but scoped to a single provider.
6.2.1 Admin – List Financial Records
/api/v1/admin/financial-records| Parameter | Description |
|---|---|
| period | Same as summary |
| booking_id | Filter by booking |
| ad_campaign_id | Filter by ad campaign |
| balance_status | IN_CURRENT_BALANCE | TRANSFERRED | REFUNDED |
| search | Free text (trip name, تفاصيل) |
6.2.2 Provider – List Own Financial Records
/api/v1/provider/financial-recordsSame payload, but only records belonging to that provider.
6.3 Payout Operations (Mark as Transferred)
From التقارير المالية screen, finance/admin may mark amounts as "تم التحويل" when bank transfers are executed.
/api/v1/admin/financial-records/{id}/mark-transferred- balance_status → TRANSFERRED
- Optional payout_reference & payout_date set
- Actual bank integration is outside current scope
6.4 Export File
Matches "تصدير" button + success modal "تم تصدير الملف بنجاح إلي ملفاتك".
/api/v1/admin/financial-records/exportResponse: File download (CSV / XLSX). Backend should log export action for auditing.
7. Refunds API
Policies around refunds are defined in trip details UI "سياسة الإلغاء" section and business-rules-and-policies.md.
Current assumption: Refunds are triggered manually by Admin/Finance, not by end user directly.
7.1 Admin – Issue Refund for Booking
/api/v1/admin/bookings/{id}/refundamount is required only if refund_type = PARTIAL.
Effects:
- Calls underlying gateway refund API (HyperPay / STC Pay)
- Creates new PaymentTransaction with status = REFUNDED or PARTIAL_REFUND
- Updates related FinancialRecord: balance_status → REFUNDED
- Updates Booking.status accordingly (likely CANCELLED)
- All detailed pro-rata calculations must strictly follow documented policy
8. Error Handling & Edge Cases
If webhook amount/currency does not match expected booking/ad campaign amounts:
- Mark PaymentTransaction.status = FAILED
- Do not confirm booking/ad campaign
- Log incident for manual review
If a webhook for the same checkout_id / transaction_reference is received more than once:
- System must treat it as idempotent
- No double increment of balances
- No extra financial records
If VAT configured in system does not match VAT used historically in existing records:
- System MUST NOT retroactively change historical vat_rate values
- VAT configuration changes are applied only to new transactions
9. Security & Permissions
- All /admin/... endpoints require admin or super_admin roles
- All /provider/... endpoints require provider_admin or provider_staff
- User-level endpoints (/my/bookings, /bookings/{id}/payment-status) require authenticated user
- Webhook endpoints are not user-authenticated, but must validate provider signatures / secrets
- Full RBAC matrix is in: 08-rbac/roles-and-permissions-matrix.md