masaruk Logo

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):
  • id
  • reference — gateway reference / checkout ID
  • user_id — the operation owner
  • booking_id (nullable) — linked booking if payment for a trip
  • ad_campaign_id (nullable) — linked ad campaign if payment for ads
  • amount — total amount including VAT (numeric, SAR)
  • currency — "SAR"
  • vat_rate — 0.15 (bookings), 0.20 (ads – pending confirmation)
  • vat_amount
  • payment_method — credit_card | mada | apple_pay | stc_pay | sadad
  • provider — hyperpay | stcpay
  • status — internal enum
EnumDescription
PENDINGCheckout created, waiting for gateway
PAIDPayment successful
FAILEDGateway rejected or error
REFUNDEDFully refunded
PARTIAL_REFUNDPartial refund executed

UI usually shows only "مكتمل" vs "فشل" vs "مسترجع" when needed.

2.2 FinancialRecord (Ledger Line)

Represents a row in التقارير المالية table (رقم المعاملة / المبلغ الإجمالي / عمولة المنصة / المبلغ الصافي / الحالة).

Minimum fields:
  • id
  • payment_transaction_id
  • booking_id (nullable)
  • ad_campaign_id (nullable)
  • gross_amount — المبلغ الإجمالي
  • platform_commission_amount — عمولة المنصة
  • net_amount — المبلغ الصافي لمزود الخدمة
  • currency — SAR
  • details — text like: "رحلة إلى العلا" / "عمرة رمضان"
  • record_date — التاريخ المعروض في الجدول
  • balance_status — internal payout status
UI LabelEnumMeaning
في الرصيد الحاليIN_CURRENT_BALANCEAmount is accrued, not yet transferred to provider
تم التحويلTRANSFERREDAmount already paid out to provider
مسترجعREFUNDEDAmount refunded to customer

3. Shared Conventions

  • All amounts in API responses are in SAR.
  • UI-specific formats like "24,560 ﷼" are applied in frontend; API returns numeric values (e.g. 24560.0).
  • Payment gateway integration details and secrets are managed server-side (no keys in clients).

4. Booking Payments – Flow & Endpoints

High-level user flow:
  1. User fills passenger & contact data → POST /api/v1/bookings
  2. Backend creates Booking with status = PENDING_PAYMENT
  3. Backend creates PaymentTransaction + gateway checkout
  4. User is redirected / opens payment widget
  5. Gateway calls MASARUK webhook + frontend is redirected to success/failure page
  6. MASARUK confirms payment, updates PaymentTransaction, Booking, and FinancialRecord

4.1 Create Payment Intent for Booking

POST/api/v1/payments/booking/{booking_id}/intent

Frontend 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
POST/api/v1/payments/webhook/hyperpay
Behavior (simplified):
  1. Resolve PaymentTransaction by checkout_id
  2. Verify signature and amount
  3. Map result code to internal status: Success → PAID, Failure → FAILED
  4. If PAID and transaction not previously processed: Update Booking status → CONFIRMED, Create/update FinancialRecord, Trigger notifications (Email/SMS to user, Dashboard widgets)
  5. 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-sadad

4.3 Get Booking Payment Status (Frontend Polling)

Used by Web/Mobile success page to poll while redirect may be delayed.

GET/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

POST/api/v1/payments/ad-campaign/{ad_campaign_id}/intent

5.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

GET/api/v1/admin/financial-reports/summary
ParameterDescription
periodtoday | this_week | this_month | custom
date_from, date_toFor custom period

6.1.2 Provider – Company Summary

GET/api/v1/provider/financial-reports/summary

Returns same structure but scoped to a single provider.

6.2.1 Admin – List Financial Records

GET/api/v1/admin/financial-records
ParameterDescription
periodSame as summary
booking_idFilter by booking
ad_campaign_idFilter by ad campaign
balance_statusIN_CURRENT_BALANCE | TRANSFERRED | REFUNDED
searchFree text (trip name, تفاصيل)

6.2.2 Provider – List Own Financial Records

GET/api/v1/provider/financial-records

Same 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.

POST/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 "تم تصدير الملف بنجاح إلي ملفاتك".

GET/api/v1/admin/financial-records/export

Response: 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

POST/api/v1/admin/bookings/{id}/refund

amount 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

EF-1Payment mismatch

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
EF-2Duplicate webhook

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
EF-3VAT inconsistency

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