Linkit

Commercial portal

Fleet accounting, payments, billable services, and partner commissions

Commercial portal

These routes require operator type Commercial. A merchant JWT is 403 (portal guard), not 501. Live Commercial JWT on 2026-09-10:

CallResult
GET /commercial/accounting-overview200 — 1,150 SAR collected, 9 payment-status rows
GET /commercial/fleet-metrics200 — 29 orgs / 7,575 orders / 677,405.57 SAR
GET /commercial/billable-services200 {items:[],total_items:0}
GET /commercial/recent-payments?page=1&perPage=5200 {page,perPage,totalItems,items}
GET /commercial/customers404 — never designed (the previous portal read the organizations collection directly)
GET /commercial/tenant-credit404 — there is no GET; credit is POST + GET …/preview

Do not invent GET /api/v1/commercial/customers or a contacts loop over /api/collections/… (that path is 404). Partner billing-impact is still absent. Leads are GET /api/v1/leads, not a commercial-prefixed twin.


Mounted

EndpointEnvelope notes
GET /api/v1/commercial/accounting-overviewSnake_case object + timestamp
GET /api/v1/commercial/fleet-metricsFleet totals + organizations[]
GET /api/v1/commercial/recent-paymentsCamelCase pager: page, perPage, totalItems, items. Rows are snake_case
GET /api/v1/commercial/balance-adjustmentsSame camelCase pager. perPage default 25, clamped to 100
GET /api/v1/commercial/billable-services{items,total_items} — catalog
POST /api/v1/commercial/billable-servicesCreate a catalog row
PATCH /api/v1/commercial/billable-services/{id}Price / metadata
POST /api/v1/commercial/billable-services/{id}/assetsUpload
POST /api/v1/commercial/billable-services/assignAttach to an install
GET /api/v1/commercial/billable-services/assignments
PATCH /api/v1/commercial/billable-services/assignments/{orgAppId}Update assignment
DELETE /api/v1/commercial/billable-services/assignments/{orgAppId}Unassign
GET /api/v1/commercial/erp-commission-ratesPartner share + tenants
GET /api/v1/commercial/partner-usersPayees
GET /api/v1/commercial/partner-commissionsBank-transfer payouts
POST /api/v1/commercial/partner-commissionsRecord a payout
GET /api/v1/commercial/partner-commissions/{id}/proofReceipt blob
GET /api/v1/commercial/tenant-credit/previewSame CheckBillingStatus as the write
POST /api/v1/commercial/tenant-creditApply credit. Not GET
GET /api/v1/leadsMarketing pipeline, cap 500. See Leads

The React commercial Billing tab already assigns billable services. Do not rebuild it.


Accounting overview (live shape)

{
  "timestamp": "2026-09-10T14:21:50Z",
  "totals": {
    "cash_collected_sar": 1150,
    "cash_collected_30d_sar": 460,
    "wallet_balance_sar": 0,
    "outstanding_branch_fees_sar": 0,
    "overdue_branch_fees_sar": 0,
    "credits_issued_sar": 1150,
    "refund_like_debits_sar": 0,
    "recognized_vat_sar": 150,
    "net_revenue_sar": 1000
  },
  "receivables": {
    "current_sar": 0,
    "days_1_to_30_sar": 0,
    "days_31_to_60_sar": 0,
    "days_61_plus_sar": 0,
    "pending_rows": 0,
    "overdue_rows": 0
  },
  "status_breakdown": [
    { "status": "COMPLETED", "count": 5, "amount": 1150 }
  ],
  "ledger_breakdown": [
    { "entry_type": "subscription_cycle_debit", "direction": "debit", "count": 5, "amount": 1150 }
  ],
  "recent_branch_fees": [],
  "reconciliation": {
    "successful_payments_sar": 1150,
    "ledger_credits_sar": 1150,
    "variance_sar": 0
  }
}

Money fields are SAR numbers, not halalas.


Fleet metrics (live shape)

{
  "timestamp": "2026-09-10T14:21:50Z",
  "total_organizations": 29,
  "active_organizations": 29,
  "inactive_organizations": 0,
  "total_branches": 2,
  "total_users": 19,
  "total_orders": 7575,
  "total_order_value": 677405.57,
  "total_collected_sar": 1150,
  "collected_last_30d_sar": 460,
  "organizations": [
    {
      "organization_id": "3xrde8yfgeqeaas",
      "name_en": "Nova Plus Medical Pharmacy",
      "name_ar": "صيدلية نوفا بلس الطبية",
      "is_active": true,
      "branch_count": 2,
      "user_count": 3,
      "order_count": 7575,
      "order_value": 677405.57,
      "collected_sar": 1150
    }
  ]
}