Frontend API Reference
Complete reference for frontend developers — authentication, endpoints, models, enums, and integration patterns.
Shipping System — Frontend API Reference
Detailed reference for frontend developers integrating with the Admin API.
Scope: Only the Admin API is exposed over HTTP today (
/api/admin/*). Shipment, route, and delivery domain models exist in the database and are documented below for context, but those endpoints are not implemented yet.
Table of Contents
- Quick Start
- Global Conventions
- Authentication
- Profile
- Admins
- Roles & Permissions
- Drivers
- Vehicles
- Driver Unavailabilities
- Driver–Vehicle Assignments
- Users (Customers)
- Domain Models Reference
- Enums Reference
- Permissions Reference
- Error Handling
- Frontend Integration Checklist
Quick Start
POST /api/admin/login
Content-Type: application/json
Accept-Language: en
{
"email": "mousa@example.com",
"password": "password"
}
Store the returned JWT and send it on every subsequent request:
GET /api/admin/drivers
Authorization: Bearer {token}
Accept: application/json
Accept-Language: en
Base URL: {APP_URL}/api — e.g. http://localhost:8000/api when running php artisan serve.
Global Conventions
Request Headers
| Header | Required | Description |
|---|---|---|
Authorization |
Yes (except login) | Bearer {jwt_token} |
Accept |
Recommended | application/json |
Accept-Language |
Optional | ar (default) or en — controls translated message text |
Content-Type |
Varies | application/json for JSON bodies; multipart/form-data when uploading images |
Response Envelope
Every API response uses this structure:
{
"status": "Success",
"message": "Data fetched successfully",
"data": {},
"statusCode": 200
}
| Field | Type | Description |
|---|---|---|
status |
"Success" | "Error" |
Outcome indicator |
message |
string | Human-readable, localized message |
data |
object | array | null | Payload (null on delete/logout) |
statusCode |
integer | HTTP status code echoed in body |
On login success, the JWT is also returned in the Authorization response header as Bearer {token}.
HTTP Methods
Updates use POST, not PUT or PATCH.
All update endpoints follow the pattern POST /api/admin/{resource}/{id}.
Content Types
| Scenario | Content-Type |
|---|---|
| JSON CRUD (no file) | application/json |
| Create/update with image (admin, driver, profile) | multipart/form-data |
| Assign/unassign vehicle | No body required |
When using multipart/form-data:
- Send scalar fields as form fields.
- Send
working_daysas repeated fields or JSON string (array). - Send
roles/permissionsas repeated fields or JSON array string. - Send
imageas a file field (max 5 MB, must be an image).
Listing, Filtering & Sorting
Most GET list endpoints accept query string parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Full-text search across model-specific columns |
sort_by |
string | Column name (must be in model's sortable list) |
sort_direction |
"asc" | "desc" |
Sort direction (default varies by model) |
page |
integer | Page number (paginated endpoints only) |
Query string values "null" and "" are automatically converted to null by middleware.
Pagination
Paginated endpoints (GET .../paginated) wrap results like this:
{
"drivers": [],
"total": 50,
"count": 10,
"per_page": 10,
"current_page": 1,
"total_pages": 5,
"links": {
"first": "http://localhost:8000/api/admin/drivers/paginated?page=1",
"last": "http://localhost:8000/api/admin/drivers/paginated?page=5",
"prev": null,
"next": "http://localhost:8000/api/admin/drivers/paginated?page=2"
}
}
The collection key matches the resource name:
| Endpoint prefix | Collection key |
|---|---|
/admins/paginated |
admins |
/roles/paginated |
roles |
/drivers/paginated |
drivers |
/vehicles/paginated |
vehicles |
/users/paginated |
users |
/driver-unavailabilities/paginated |
driver_unavailabilities |
Page size is fixed at 10 per page.
Authentication
All routes under /api/admin/* except POST /login require a valid JWT in the Authorization header.
- Guard:
admin - Library: JWT Auth (
tymon/jwt-auth) - Token TTL: Returned as
expires_in(seconds) in login response. Configured viaJWT_TTLenv (minutes); if unset, token may not expire.
POST /api/admin/login
Authenticate an admin and receive a JWT.
Auth required: No
Request body:
| Field | Type | Required | Validation |
|---|---|---|---|
email |
string | Yes | Valid email |
password |
string | Yes | Non-empty string |
fcm_token |
string | No | Push notification device token; stored on admin record |
Example request body:
{
"email": "mousa@example.com",
"password": "SecurePass123!",
"fcm_token": "device-fcm-token-abc123"
}
Success response 200:
{
"status": "Success",
"message": "User successfully signed in",
"data": {
"admin": {
"id": 1,
"name": "mousa",
"email": "mousa@example.com",
"roles": ["operations_manager"],
"permission_groups": [
{
"group": "Driver",
"group_label": "Drivers",
"permissions": [
{
"id": 1,
"name": "ViewAny:Driver",
"display_name": "View Any",
"group": "Driver"
}
]
}
]
},
"token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"token_type": "bearer",
"expires_in": 3600
},
"statusCode": 200
}
Error responses:
| Status | When |
|---|---|
401 |
Invalid email/password (credentialsError) |
422 |
Validation failed (missing email/password) |
500 |
Token generation failed (couldNotCreateToken) |
POST /api/admin/logout
Invalidate the current JWT session.
Auth required: Yes
Request body: None
Success response 200:
{
"status": "Success",
"message": "User successfully signed out",
"data": null,
"statusCode": 200
}
Error responses:
| Status | When |
|---|---|
403 |
No token provided (Unauthenticated) |
500 |
Logout failed (couldNotLogout) |
Profile
Manage the currently authenticated admin's own profile. Does not require admin-management permissions.
GET /api/admin/profile
Permission required: None (authentication only)
Success response 200: Returns an AdminResource (see Admins) with:
is_current_admin: truepermission_groupsincludedrolesincluded
POST /api/admin/profile
Update the authenticated admin's profile.
Permission required: None (authentication only)
Request body (JSON or multipart):
| Field | Type | Required | Validation |
|---|---|---|---|
name |
string | No | Max 255 chars |
email |
string | No | Valid email, unique among admins |
password |
string | No | Laravel password defaults |
image |
file | No | Image, max 5 MB |
Example request body:
{
"name": "mousa",
"email": "mousa.updated@example.com",
"password": "NewSecurePass123!"
}
Success response 200: Updated AdminResource with message profileUpdatedSuccessfully.
Admins
Back-office user management.
Permission prefix: Admin (e.g. ViewAny:Admin, Create:Admin)
Hidden admin accounts (configured via HIDDEN_ADMIN env) are excluded from listings.
Endpoints
| Method | Path | Description | Permission |
|---|---|---|---|
GET |
/api/admin/admins |
List all admins | ViewAny:Admin |
GET |
/api/admin/admins/paginated |
List paginated | ViewAny:Admin |
GET |
/api/admin/admins/{id} |
Get single admin | View:Admin |
POST |
/api/admin/admins |
Create admin | Create:Admin |
POST |
/api/admin/admins/{id} |
Update admin | Update:Admin |
DELETE |
/api/admin/admins/{id} |
Delete admin | Delete:Admin |
List Query Parameters
| Parameter | Description |
|---|---|
search |
Searches name, email |
role |
Filter by role name (exact match) |
sort_by |
name, email, created_at |
sort_direction |
asc or desc (default: asc by name) |
Create Request Body
| Field | Type | Required | Validation |
|---|---|---|---|
name |
string | Yes | Max 255 |
email |
string | Yes | Valid email, unique |
password |
string | Yes | Laravel password defaults |
image |
file | No | Image, max 5 MB |
roles |
string[] | No | Array of existing role names |
Example request body:
{
"name": "mousa",
"email": "mousa@example.com",
"password": "SecurePass123!",
"roles": ["operations_manager"]
}
Update Request Body
Same fields as create, all optional (sometimes rules apply). Omit password to keep current password. Send roles: [] to remove all roles.
Example request body:
{
"name": "mousa",
"email": "mousa.admin@example.com",
"roles": ["super_admin"]
}
Admin Resource Shape
{
"id": 1,
"name": "mousa",
"email": "mousa@example.com",
"image": "http://localhost:8000/storage/1/admin_image.jpg",
"roles": ["super_admin"],
"permission_groups": [],
"is_current_admin": false,
"created_at": "2026-01-15T10:00:00.000000Z",
"updated_at": "2026-01-15T10:00:00.000000Z"
}
| Field | Notes |
|---|---|
image |
Full URL to profile image, or empty string if none |
roles |
Array of role name strings |
permission_groups |
Only included on GET /profile and GET /admins/{id} |
is_current_admin |
true if this admin is the one making the request |
Delete Constraints
- Cannot delete your own account →
403with messagecannotDeleteCurrentAdmin
Roles & Permissions
Role-based access control using Spatie Permission (guard: admin).
Permission prefixes: Role, Permission
Endpoints
| Method | Path | Description | Permission |
|---|---|---|---|
GET |
/api/admin/permissions |
All permissions grouped | ViewAny:Permission |
GET |
/api/admin/roles |
List all roles | ViewAny:Role |
GET |
/api/admin/roles/paginated |
List paginated | ViewAny:Role |
GET |
/api/admin/roles/{id} |
Get single role | View:Role |
POST |
/api/admin/roles |
Create role | Create:Role |
POST |
/api/admin/roles/{id} |
Update role | Update:Role |
POST |
/api/admin/roles/{id}/permissions |
Sync permissions only | Update:Role |
DELETE |
/api/admin/roles/{id} |
Delete role | Delete:Role |
List Query Parameters (roles)
| Parameter | Description |
|---|---|
search |
Searches role name |
sort_by |
name, created_at |
sort_direction |
asc or desc (default: asc by name) |
Create Role Request Body
| Field | Type | Required | Validation |
|---|---|---|---|
name |
string | Yes | Unique per guard, max 255 |
permissions |
string[] | No | Array of permission name strings |
Example request body:
{
"name": "warehouse_manager",
"permissions": ["ViewAny:Driver", "Create:Driver", "ViewAny:Vehicle"]
}
Update Role Request Body
| Field | Type | Required | Validation |
|---|---|---|---|
name |
string | No | Unique per guard, max 255 |
permissions |
string[] | No | Replaces all permissions when provided |
Example request body:
{
"name": "warehouse_manager",
"permissions": ["ViewAny:Driver", "Update:Driver"]
}
Sync Permissions Request Body
POST /api/admin/roles/{id}/permissions
| Field | Type | Required | Validation |
|---|---|---|---|
permissions |
string[] | Yes | Array of permission name strings |
Example request body:
{
"permissions": ["ViewAny:Driver", "Create:Driver", "ViewAny:Vehicle", "Create:Vehicle"]
}
Success message: permissionsAssignedSuccessfully
Role Resource Shape
{
"id": 2,
"name": "warehouse_manager",
"guard_name": "admin",
"permission_groups": [
{
"group": "Driver",
"group_label": "Drivers",
"permissions": [
{
"id": 1,
"name": "ViewAny:Driver",
"display_name": "View Any",
"group": "Driver"
}
]
}
],
"created_at": "2026-01-15T10:00:00.000000Z",
"updated_at": "2026-01-15T10:00:00.000000Z"
}
Permission Group Shape
Used in login, profile, roles, and the permissions list:
{
"group": "Driver",
"group_label": "Drivers",
"permissions": [
{
"id": 1,
"name": "ViewAny:Driver",
"display_name": "View Any",
"group": "Driver"
}
]
}
Constraints
- Super admin role cannot be modified or deleted →
403(cannotModifySuperAdmin)
Drivers
Delivery driver management.
Permission prefix: Driver
Endpoints
| Method | Path | Description | Permission |
|---|---|---|---|
GET |
/api/admin/drivers |
List all drivers | ViewAny:Driver |
GET |
/api/admin/drivers/paginated |
List paginated | ViewAny:Driver |
GET |
/api/admin/drivers/{id} |
Get single driver | View:Driver |
POST |
/api/admin/drivers |
Create driver | Create:Driver |
POST |
/api/admin/drivers/{id} |
Update driver | Update:Driver |
DELETE |
/api/admin/drivers/{id} |
Delete driver | Delete:Driver |
GET |
/api/admin/drivers/{id}/vehicle-assignments |
Vehicle assignments | ViewAny:DriverVehicleAssignment |
GET |
/api/admin/drivers/{id}/unavailabilities |
Unavailability periods | ViewAny:DriverUnavailability |
POST |
/api/admin/drivers/{driverId}/vehicles/{vehicleId}/assign |
Assign vehicle | Create:DriverVehicleAssignment |
POST |
/api/admin/drivers/{driverId}/vehicles/{vehicleId}/unassign |
Unassign vehicle | Update:DriverVehicleAssignment |
List Query Parameters
| Parameter | Type | Description |
|---|---|---|
search |
string | Searches name, phone, email, driver_number, license_number |
is_active |
boolean | Filter by active status |
lat |
float | Latitude for nearby search (requires lng) |
lng |
float | Longitude for nearby search (requires lat) |
radius |
float | Search radius in km (default: 10) |
work_start_time |
time | Filter drivers whose shift overlaps this start time |
work_end_time |
time | Filter drivers whose shift overlaps this end time |
work_start_time_from |
time | Minimum shift start time |
work_start_time_to |
time | Maximum shift start time |
work_end_time_from |
time | Minimum shift end time |
work_end_time_to |
time | Maximum shift end time |
sort_by |
string | See sortable columns below |
sort_direction |
string | asc or desc |
Sortable columns: name, phone, driver_number, work_start_time, work_end_time, created_at, distance
When lat/lng are provided, results include a distance field (km) and default-sort by nearest first unless sort_by is explicitly set.
Time format: HH:MM:SS or HH:MM (auto-normalized to HH:MM:SS).
Create Request Body
| Field | Type | Required | Validation |
|---|---|---|---|
name |
string | Yes | Max 255 |
phone |
string | Yes | Max 50 |
phone_country |
string | Yes | Max 10 (e.g. +963) |
email |
string | No | Valid email, unique |
password |
string | Yes | Laravel password defaults |
address |
string | Yes | |
license_number |
string | No | Max 255 |
working_days |
string[] | Yes | Min 1 item; see Working Days |
work_start_time |
time | Yes | Must differ from work_end_time |
work_end_time |
time | Yes | Must differ from work_start_time |
lat |
float | No | -90 to 90 |
lng |
float | No | -180 to 180 |
fcm_token |
string | No | Push notification token |
is_active |
boolean | No | Default: true |
image |
file | No | Image, max 5 MB |
driver_number |
string | No | Unique; auto-generated 6-digit number if omitted |
Example request body:
{
"name": "mousa",
"phone": "944123456",
"phone_country": "+963",
"email": "mousa.driver@example.com",
"password": "SecurePass123!",
"address": "Damascus, Syria",
"license_number": "SY-12345",
"working_days": ["sun", "mon", "tue", "wed", "thu"],
"work_start_time": "08:00:00",
"work_end_time": "17:00:00",
"lat": 33.5138,
"lng": 36.2765,
"is_active": true
}
Update Request Body
Same fields as create. All fields optional except where sometimes + required applies. Password optional (omit to keep current).
Example request body:
{
"name": "mousa",
"phone": "944654321",
"phone_country": "+963",
"work_start_time": "09:00:00",
"work_end_time": "18:00:00",
"is_active": true
}
Driver Resource Shape
{
"id": 1,
"driver_number": "482910",
"name": "mousa",
"phone": "944123456",
"phone_country": "+963",
"email": "mousa.driver@example.com",
"image": "http://localhost:8000/storage/2/driver_image.jpg",
"address": "Damascus, Syria",
"license_number": "DL-12345",
"working_days": ["sun", "mon", "tue", "wed", "thu"],
"work_start_time": "08:00:00",
"work_end_time": "17:00:00",
"lat": 24.7136,
"lng": 46.6753,
"is_active": true,
"created_at": "2026-01-15T10:00:00.000000Z",
"updated_at": "2026-01-15T10:00:00.000000Z",
"distance": 3.2
}
| Field | Notes |
|---|---|
distance |
Only present when nearby filter (lat/lng) is used |
working_days |
JSON array of day codes |
image |
Full URL or empty string |
Vehicles
Fleet vehicle management.
Permission prefix: Vehicle
Endpoints
| Method | Path | Description | Permission |
|---|---|---|---|
GET |
/api/admin/vehicles |
List all vehicles | ViewAny:Vehicle |
GET |
/api/admin/vehicles/paginated |
List paginated | ViewAny:Vehicle |
GET |
/api/admin/vehicles/{id} |
Get single vehicle | View:Vehicle |
POST |
/api/admin/vehicles |
Create vehicle | Create:Vehicle |
POST |
/api/admin/vehicles/{id} |
Update vehicle | Update:Vehicle |
DELETE |
/api/admin/vehicles/{id} |
Delete vehicle | Delete:Vehicle |
List Query Parameters
| Parameter | Description |
|---|---|
search |
Searches plate_number |
owner_type |
Exact match: company or driver |
is_active |
Boolean filter |
sort_by |
plate_number, owner_type, max_weight, max_volume, created_at |
sort_direction |
asc or desc (default: asc by plate_number) |
Create Request Body
| Field | Type | Required | Validation |
|---|---|---|---|
plate_number |
string | Yes | Unique, max 255 |
owner_type |
string | Yes | company or driver — see OwnerTypes |
owner_id |
integer | Conditional | Required when owner_type is driver; must be a valid driver ID. Must not be sent when owner_type is company |
max_weight |
number | Yes | Min 0 (kg) |
max_volume |
number | Yes | Min 0 (m³) |
Example request body:
{
"plate_number": "DMS-1234",
"owner_type": "company",
"max_weight": 1500,
"max_volume": 12.5
}
Example request body (driver-owned):
{
"plate_number": "DMS-5678",
"owner_type": "driver",
"owner_id": 1,
"max_weight": 2000,
"max_volume": 15
}
Update Request Body
| Field | Type | Required | Validation |
|---|---|---|---|
plate_number |
string | No | Unique, max 255 |
owner_type |
string | No | company or driver |
owner_id |
integer | Conditional | Same rules as create |
max_weight |
number | No | Min 0 |
max_volume |
number | No | Min 0 |
is_active |
boolean | No |
Example request body:
{
"plate_number": "DMS-9999",
"max_weight": 1800,
"max_volume": 14,
"is_active": false
}
Vehicle Resource Shape
{
"id": 1,
"plate_number": "ABC-1234",
"owner_type": "company",
"owner_type_label": "الشركة",
"owner_id": null,
"max_weight": 1500,
"max_volume": 12.5,
"is_active": true,
"created_at": "2026-01-15T10:00:00.000000Z",
"updated_at": "2026-01-15T10:00:00.000000Z"
}
| Field | Notes |
|---|---|
owner_type_label |
Localized Arabic label (API always returns Arabic label regardless of Accept-Language) |
owner_id |
null for company-owned vehicles; driver ID for driver-owned |
Driver Unavailabilities
Time-off / unavailability blocks for drivers.
Permission prefix: DriverUnavailability
Endpoints
| Method | Path | Description | Permission |
|---|---|---|---|
GET |
/api/admin/driver-unavailabilities |
List all | ViewAny:DriverUnavailability |
GET |
/api/admin/driver-unavailabilities/paginated |
List paginated | ViewAny:DriverUnavailability |
GET |
/api/admin/driver-unavailabilities/{id} |
Get single | View:DriverUnavailability |
POST |
/api/admin/driver-unavailabilities |
Create | Create:DriverUnavailability |
POST |
/api/admin/driver-unavailabilities/{id} |
Update | Update:DriverUnavailability |
DELETE |
/api/admin/driver-unavailabilities/{id} |
Delete | Delete:DriverUnavailability |
Also accessible via GET /api/admin/drivers/{id}/unavailabilities.
List Query Parameters
| Parameter | Description |
|---|---|
driver_id |
Filter by driver ID (exact) |
sort_by |
start_date, end_date, created_at |
sort_direction |
Default: desc by start_date |
Create Request Body
| Field | Type | Required | Validation |
|---|---|---|---|
driver_id |
integer | Yes | Must exist in drivers table |
start_date |
date | Yes | ISO date or datetime |
end_date |
date | Yes | Must be after start_date |
reason |
string | No | Free text |
Example request body:
{
"driver_id": 1,
"start_date": "2026-06-01",
"end_date": "2026-06-05",
"reason": "Annual leave"
}
Update Request Body
Same fields, all optional. If both dates are provided on update, end_date must still be after start_date.
Example request body:
{
"start_date": "2026-06-01",
"end_date": "2026-06-10",
"reason": "Extended leave"
}
Driver Unavailability Resource Shape
{
"id": 1,
"driver_id": 5,
"start_date": "2026-06-01T00:00:00.000000Z",
"end_date": "2026-06-05T00:00:00.000000Z",
"reason": "Annual leave",
"created_at": "2026-05-20T10:00:00.000000Z",
"updated_at": "2026-05-20T10:00:00.000000Z"
}
Driver–Vehicle Assignments
Links drivers to vehicles for operational use. A vehicle can only have one active assignment at a time (released_at === null).
Permission prefix: DriverVehicleAssignment
Endpoints
| Method | Path | Description | Permission |
|---|---|---|---|
GET |
/api/admin/drivers/{id}/vehicle-assignments |
List assignments for driver | ViewAny:DriverVehicleAssignment |
POST |
/api/admin/drivers/{driverId}/vehicles/{vehicleId}/assign |
Assign vehicle to driver | Create:DriverVehicleAssignment |
POST |
/api/admin/drivers/{driverId}/vehicles/{vehicleId}/unassign |
Release assignment | Update:DriverVehicleAssignment |
Assign
No request body. Creates a record with:
assigned_at= current timestampreleased_at=null
Error: 422 if vehicle already has an active assignment (vehicleAlreadyAssigned)
Unassign
No request body. Sets released_at to current timestamp on the active assignment.
Error: 404 if no active assignment exists (vehicleAssignmentNotFound)
Driver Vehicle Assignment Resource Shape
{
"id": 1,
"driver_id": 3,
"vehicle_id": 7,
"assigned_at": "2026-06-01T08:00:00.000000Z",
"released_at": null,
"vehicle": {
"id": 7,
"plate_number": "XYZ-5678",
"owner_type": "company",
"owner_type_label": "الشركة",
"owner_id": null,
"max_weight": 2000,
"max_volume": 15,
"is_active": true,
"created_at": "...",
"updated_at": "..."
},
"driver": {
"id": 3,
"driver_number": "482910",
"name": "mousa"
},
"created_at": "2026-06-01T08:00:00.000000Z",
"updated_at": "2026-06-01T08:00:00.000000Z"
}
| Field | Notes |
|---|---|
vehicle |
Nested VehicleResource when relation is loaded |
driver |
Nested DriverResource when relation is loaded |
released_at |
null = currently assigned |
Users (Customers)
End customers who place shipments. These are not admin accounts.
Permission prefix: User
Endpoints
| Method | Path | Description | Permission |
|---|---|---|---|
GET |
/api/admin/users |
List all users | ViewAny:User |
GET |
/api/admin/users/paginated |
List paginated | ViewAny:User |
GET |
/api/admin/users/{id} |
Get single user | View:User |
POST |
/api/admin/users |
Create user | Create:User |
POST |
/api/admin/users/{id} |
Update user | Update:User |
DELETE |
/api/admin/users/{id} |
Delete user | Delete:User |
List Query Parameters
| Parameter | Description |
|---|---|
search |
Searches name, phone, email, company_name |
sort_by |
name, phone, email, company_name, created_at |
sort_direction |
asc or desc (default: asc by name) |
Create Request Body
| Field | Type | Required | Validation |
|---|---|---|---|
name |
string | Yes | Max 255 |
phone |
string | Yes | Max 50; unique per phone_country |
phone_country |
string | Yes | Max 10 |
email |
string | No | Valid email, unique |
company_name |
string | No |
Example request body:
{
"name": "mousa",
"phone": "944123456",
"phone_country": "+963",
"email": "mousa@example.com",
"company_name": "Mousa Trading Co."
}
Update Request Body
Same fields, all optional. Phone uniqueness is re-validated when phone or phone_country changes.
Example request body:
{
"name": "mousa",
"phone": "944654321",
"phone_country": "+963",
"company_name": "Mousa Logistics"
}
User Resource Shape
{
"id": 1,
"name": "mousa",
"phone": "944123456",
"phone_country": "+963",
"email": "mousa@example.com",
"company_name": "Mousa Trading Co.",
"created_at": "2026-01-15T10:00:00.000000Z",
"updated_at": "2026-01-15T10:00:00.000000Z"
}
Domain Models Reference
Currently Exposed via API
| Model | Table | Description | Key Fields |
|---|---|---|---|
| Admin | admins |
Back-office users | name, email, password, fcm_token |
| Role | roles |
Spatie roles (guard: admin) |
name, guard_name |
| Permission | permissions |
Spatie permissions | name, guard_name |
| Driver | drivers |
Delivery drivers | driver_number, name, phone, working_days, work_start_time, work_end_time, lat, lng, is_active |
| Vehicle | vehicles |
Fleet vehicles | plate_number, owner_type, owner_id, max_weight, max_volume, is_active |
| DriverVehicleAssignment | driver_vehicle_assignments |
Driver ↔ vehicle link | driver_id, vehicle_id, assigned_at, released_at |
| DriverUnavailability | driver_unavailabilities |
Driver time-off | driver_id, start_date, end_date, reason |
| User | users |
Customers / shippers | name, phone, phone_country, email, company_name |
Planned Domain (Not Yet in API)
These models exist in the database and will power shipment/route features. No HTTP endpoints exist for them yet.
Shipment (shipments)
Core delivery order placed by a customer.
| Field | Type | Enum / Notes |
|---|---|---|
shipment_number |
string | Unique identifier |
user_id |
integer | FK → users |
user_name |
string | Denormalized customer name |
delivery_date |
datetime | Target delivery date |
status |
string | ShipmentStatuses |
type |
string | ShipmentTypes |
payment_type |
string | PaymentTypes |
cod_amount |
float | Required when payment is COD |
total_weight |
float | kg |
total_volume |
float | m³ |
notes |
string | Optional |
Relationships:
user→ Usershipment_items→ ShipmentItem[]shipment_stops→ ShipmentStop[]shipment_events→ ShipmentEvent[]proof_of_deliveries→ ProofOfDelivery[]failed_deliveries→ FailedDelivery[]
ShipmentItem (shipment_items)
Individual items within a shipment.
| Field | Type | Notes |
|---|---|---|
shipment_id |
integer | FK → shipments |
name |
string | Item name |
weight |
float | kg |
length, width, height |
float | Dimensions |
quantity |
integer | |
description |
string | Optional |
declared_value |
float | Optional |
ShipmentStop (shipment_stops)
Pickup, delivery, or intermediate stops on a shipment route.
| Field | Type | Enum / Notes |
|---|---|---|
shipment_id |
integer | FK → shipments |
type |
string | ShipmentStopTypes |
contact_name |
string | |
phone, phone_country |
string | |
country, city, area |
string | Address components |
street, building, floor, apartment |
string | |
lat, lng |
float | Coordinates |
full_address |
string | Formatted address |
sequence |
integer | Order within shipment |
ShipmentEvent (shipment_events)
Audit log / timeline entries for a shipment.
| Field | Type | Enum / Notes |
|---|---|---|
shipment_id |
integer | FK → shipments |
event_type |
string | ShipmentEvents |
data |
string | JSON payload (optional) |
causer_type, causer_id |
string, int | Polymorphic causer |
causer_name |
string | Denormalized causer name |
notes |
string | Optional |
Route (routes)
Optimized daily route assigned to a driver and vehicle.
| Field | Type | Enum / Notes |
|---|---|---|
driver_id |
integer | FK → drivers |
vehicle_id |
integer | FK → vehicles |
route_date |
datetime | Date of the route |
status |
string | RouteStatuses |
total_stops |
integer | |
optimized_distance |
float | km |
duration |
float | minutes |
Relationships:
driver→ Drivervehicle→ Vehicleroute_stops→ RouteStop[]route_assignments→ RouteAssignment[]
RouteStop (route_stops)
An ordered stop on a driver's route, linked to a shipment stop.
| Field | Type | Enum / Notes |
|---|---|---|
route_id |
integer | FK → routes |
shipment_stop_id |
integer | FK → shipment_stops |
status |
string | RouteStopStatuses |
distance_from_previous_km |
float | |
estimated_minutes_from_previous |
float | |
arrived_at, completed_at |
datetime | |
sequence |
integer | Order on route |
RouteAssignment (route_assignments)
Tracks driver assignment history to a route.
| Field | Type | Notes |
|---|---|---|
route_id |
integer | FK → routes |
driver_id |
integer | FK → drivers |
assigned_at |
datetime | |
unassigned_at |
datetime | Null while active |
ProofOfDelivery (proof_of_deliveries)
Delivery confirmation record.
| Field | Type | Notes |
|---|---|---|
shipment_id |
integer | FK → shipments |
receiver_name |
string | |
receiver_phone, receiver_phone_country |
string | |
delivered_at |
datetime | |
notes |
string | |
created_by_type, created_by_id |
string, int | Polymorphic creator |
created_by_name |
string |
FailedDelivery (failed_deliveries)
Record of a failed delivery attempt.
| Field | Type | Notes |
|---|---|---|
shipment_id |
integer | FK → shipments |
reason_code |
string | Failure reason code |
notes |
string | |
created_by_type, created_by_id |
string, int | Polymorphic creator |
created_by_name |
string |
StaticContent (static_contents)
Key-value CMS / app configuration store (not yet in API).
| Field | Type | Notes |
|---|---|---|
key |
string | Primary key; see StaticContentTypes |
value |
string | Plain text or JSON-encoded value |
Entity Relationship Diagram (Overview)
User ──< Shipment ──< ShipmentItem
──< ShipmentStop ──< RouteStop >── Route >── Driver
──< ShipmentEvent └── Vehicle
──< ProofOfDelivery
──< FailedDelivery
Driver ──< DriverVehicleAssignment >── Vehicle
──< DriverUnavailability
──< RouteAssignment >── Route
Admin ──< Role ──< Permission
Enums Reference
All enum values are snake_case strings. Store them as string constants in the frontend.
OwnerTypes
Used in API today — vehicle ownership.
| Value | Arabic Label | Rules |
|---|---|---|
company |
الشركة | owner_id must be null |
driver |
سائق | owner_id must be a valid driver ID |
API returns both owner_type (value) and owner_type_label (Arabic label).
Suggested TypeScript:
type OwnerType = 'company' | 'driver';
ShipmentStatuses
Planned — shipment lifecycle state.
| Value | Arabic Label | Suggested UI Color |
|---|---|---|
draft |
مسودة | secondary |
pending |
في الانتظار | warning |
assigned |
تم التخصيص لسائق | primary |
pickup_in_progress |
قيد التحصيل | warning |
picked_up |
تم التحصيل | success |
at_hub |
في المخزن | info |
out_for_delivery |
قيد التسليم | primary |
delivered |
تم التسليم | success |
delivery_failed |
فشل التسليم | danger |
returned |
مرتجع | warning |
cancelled |
تم الإلغاء | danger |
Typical flow:
draft → pending → assigned → pickup_in_progress → picked_up → at_hub
→ out_for_delivery → delivered
↘ delivery_failed → returned
Any state → cancelled
ShipmentTypes
| Value | Arabic Label |
|---|---|
domestic |
محلي |
international |
دولية |
ShipmentStopTypes
| Value | Arabic Label | Description |
|---|---|---|
pickup |
تحصيل | Collect goods from sender |
delivery |
تسليم | Deliver to recipient |
stop |
موقف | Intermediate stop |
PaymentTypes
| Value | Arabic Label | Notes |
|---|---|---|
cod |
عند الاستلام | Cash on delivery; requires cod_amount |
prepaid |
مقدما | Paid upfront |
RouteStatuses
| Value | Arabic Label |
|---|---|
draft |
مسودة |
assigned |
تم تخصيص السائق |
active |
فعال |
completed |
مكتمل |
cancelled |
ملغي |
RouteStopStatuses
| Value | Arabic Label |
|---|---|
pending |
قيد الانتظار |
arrived |
تم الوصول |
completed |
مكتمل |
failed |
فشل |
skipped |
تخطي |
ShipmentEvents
Timeline event types logged on shipments.
| Value | Arabic Label |
|---|---|
shipment_created |
تم إنشاء الشحنة |
driver_assigned |
تم تخصيص السائق |
route_created |
تم إنشاء الرحلة |
pickup_started |
تم بدء التحصيل |
pickup_completed |
تم إنهاء التحصيل |
delivery_failed |
فشل التسليم |
pod_uploaded |
تم تحميل إثبات التوصيل |
MediaTypes
Internal media collection names (used for image uploads).
| Value | Used For |
|---|---|
admin_image |
Admin profile photos |
driver_image |
Driver profile photos |
user_image |
User profile photos (future) |
StaticContentTypes
CMS / app configuration keys (not yet in API).
| Value | Arabic Label |
|---|---|
privacy_policy |
سياسة الخصوصية |
commission |
عمولة الإدارة |
social_media |
المواقع الاجتماعية |
android_app_version |
نسخة التطبيق للاندرويد |
ios_app_version |
نسخة التطبيق لل IOS |
android_provider_app_version |
نسخة التطبيق للاندرويد للمزود |
ios_provider_app_version |
نسخة التطبيق لل IOS للمزود |
NotificationTypes
Push notification categories (PHP backed enum).
| Value |
|---|
general |
wallet_deposit |
wallet_withdraw |
new_offer |
offer_accepted |
offer_rejected |
order_status_changed |
new_order |
Working Days (not a PHP enum)
Driver schedule days. Accepted as array values in create/update requests.
| Value | Day |
|---|---|
sun |
Sunday |
mon |
Monday |
tue |
Tuesday |
wed |
Wednesday |
thu |
Thursday |
fri |
Friday |
sat |
Saturday |
Suggested TypeScript:
type WorkingDay = 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat';
Permissions Reference
Permissions control what each admin can do. Check them client-side to show/hide UI elements.
Naming Convention
{Action}:{Model}
| Action | Description |
|---|---|
ViewAny |
List/index access |
View |
View single record |
Create |
Create new record |
Update |
Edit existing record |
Delete |
Delete record |
Reorder |
Reorder records (if applicable) |
Examples:
ViewAny:Driver— can list driversCreate:Vehicle— can create vehiclesUpdate:Admin— can edit adminsDelete:Role— can delete roles
Custom Permissions
These do not map to a CRUD model:
| Permission | Description |
|---|---|
Export:Reports |
Export reports |
Send:Notifications |
Send push notifications |
Manage:AppSettings |
Manage app settings |
Assign:Routes |
Assign routes to drivers |
Track:Deliveries |
Track live deliveries |
How to Check Permissions on Frontend
After login, inspect data.admin.permission_groups:
function hasPermission(
permissionGroups: PermissionGroup[],
permissionName: string
): boolean {
return permissionGroups.some(group =>
group.permissions.some(p => p.name === permissionName)
);
}
// Usage
if (hasPermission(admin.permission_groups, 'Create:Driver')) {
// Show "Add Driver" button
}
Super admin role has all permissions implicitly.
Error Handling
HTTP Status Codes
| Code | Meaning | When |
|---|---|---|
200 |
Success | Normal operation |
401 |
Unauthorized | Missing/invalid permission, wrong credentials |
403 |
Forbidden | Not authenticated (no/invalid token) |
404 |
Not Found | Route or resource not found |
422 |
Validation Error | Invalid request body/query |
500 |
Server Error | Unexpected failure |
Common Error Messages
| Message Key | English Text | Status |
|---|---|---|
credentialsError |
Wrong Credentials | 401 |
Unauthenticated |
Please login first | 403 |
Unauthorized |
You do not have permissions to perform this action | 401 |
cannotDeleteCurrentAdmin |
You cannot delete your own admin account | 403 |
cannotModifySuperAdmin |
Super admin role cannot be modified | 403 |
vehicleAlreadyAssigned |
This vehicle is already assigned to a driver | 422 |
vehicleAssignmentNotFound |
No active vehicle assignment found for this driver | 404 |
couldNotCreateToken |
Could not create authentication token | 500 |
couldNotLogout |
Could not log out | 500 |
Validation errors return the first validation message as message.
Error Response Shape
{
"status": "Error",
"message": "Wrong Credentials",
"data": null,
"statusCode": 401
}
Frontend Integration Checklist
- Store JWT from login response (
data.token) - Send
Authorization: Bearer {token}on every authenticated request - Set
Accept-Language: enorarfor localized messages - Use
POSTfor all updates (not PUT/PATCH) - Use
multipart/form-datawhen uploadingimagefields - Gate UI by checking
permission_groupsfrom login/profile response - Handle the standard
{ status, message, data, statusCode }envelope - Use paginated endpoints with
pagequery param for tables - Pass
search,sort_by,sort_directionfor filterable lists - For vehicles: enforce
owner_idrules based onowner_type - For drivers: send
working_daysas array; times asHH:MMorHH:MM:SS - Shipment/route features: use enums from this doc but wait for backend API routes
Route Index (Quick Reference)
| Method | Path |
|---|---|
POST |
/api/admin/login |
POST |
/api/admin/logout |
GET |
/api/admin/profile |
POST |
/api/admin/profile |
GET |
/api/admin/permissions |
GET/POST/DELETE |
/api/admin/roles, /api/admin/roles/paginated, /api/admin/roles/{id}, /api/admin/roles/{id}/permissions |
GET/POST/DELETE |
/api/admin/admins, /api/admin/admins/paginated, /api/admin/admins/{id} |
GET/POST/DELETE |
/api/admin/drivers, /api/admin/drivers/paginated, /api/admin/drivers/{id} |
GET/POST |
/api/admin/drivers/{id}/vehicle-assignments, .../assign, .../unassign |
GET |
/api/admin/drivers/{id}/unavailabilities |
GET/POST/DELETE |
/api/admin/vehicles, /api/admin/vehicles/paginated, /api/admin/vehicles/{id} |
GET/POST/DELETE |
/api/admin/driver-unavailabilities, .../paginated, .../{id} |
GET/POST/DELETE |
/api/admin/users, /api/admin/users/paginated, /api/admin/users/{id} |
Generated from the shipping_system codebase. Last updated: June 2026.