# Driver API Documentation

This document provides API documentation for mobile app developers integrating with the Driver app backend APIs.

---

## Table of Contents

1. [Getting Started](#getting-started)
2. [API Format & Headers](#api-format--headers)
3. [API List](#api-list)
4. [API Details](#api-details)
5. [WebSocket Integration](#websocket-integration)
6. [Implementation Guidelines](#implementation-guidelines)

---

## Getting Started

### Base URL Configuration

```
Production: https://api.yourdomain.com
Staging: https://staging-api.yourdomain.com
Development: http://localhost:8000
```

### Authentication Flow

1. Check force update version on app launch
2. User logs in → receive JWT token
3. Save device token for push notifications
4. Use token in `Authorization: Bearer {token}` header for all authenticated requests
5. Handle 401 errors by redirecting to login

### Token Storage

- **iOS:** Keychain Services
- **Android:** EncryptedSharedPreferences or Android Keystore
- Token expires after 24 hours (check backend configuration)

---

## API Format & Headers

### Request Headers

**For JSON Requests:**

```
Content-Type: application/json
Authorization: Bearer {token}  // Required for authenticated endpoints
Accept: application/json
```

**For FormData (File Uploads):**

```
Content-Type: multipart/form-data
Authorization: Bearer {token}
Accept: application/json
```

### Response Format

**Success:**

```json
{
    "status": "success",
    "message": "Operation successful",
    "data": {}
}
```

**Error:**

```json
{
    "status": "error",
    "message": "Error message",
    "errors": {}
}
```

### HTTP Status Codes

- `200` - Success
- `400` - Bad Request
- `401` - Unauthorized → Redirect to login
- `403` - Forbidden
- `422` - Validation Error
- `500` - Server Error

---

## API List


| #   | Method | Endpoint                                            | Description                                       |
| --- | ------ | --------------------------------------------------- | ------------------------------------------------- |
| 1   | GET    | `/api/configurations/force-update-version`          | Check minimum app version                         |
| 2   | POST   | `/api/login`                                        | Authenticate driver                               |
| 3   | POST   | `/api/mobile/save-device-token`                     | Register for push notifications                   |
| 4   | POST   | `/api/forgot-password`                              | Request password reset (web)                      |
| 4a  | POST   | `/api/mobile/forgot-password`                       | Request/Resend OTP code for password reset        |
| 4b  | POST   | `/api/mobile/verify-otp`                            | Verify OTP code                                   |
| 4c  | POST   | `/api/mobile/reset-password`                        | Reset password with verified OTP                  |
| 5   | GET    | `/api/get-user-details`                             | Get driver profile                                |
| 6   | GET    | `/api/schedules`                                    | Get schedule list                                 |
| 7   | GET    | `/api/get-all-available-trailers-list-for-location` | Get available trailers                            |
| 8   | GET    | `/api/get-all-door-list-for-schedule`               | Get available doors                               |
| 9   | POST   | `/api/schedules/{id}/log-time`                      | Log schedule time (in/out/completed/parked)       |
| 10  | POST   | `/api/schedules/update-by-values/{id}`              | Update trailer/door/comments                      |
| 10a | POST   | `/api/schedules/offline-sync`                       | Batch sync schedule updates & log times (offline) |
| 11  | POST   | `/api/update-user-details`                          | Update driver profile                             |
| 12  | DELETE | `/api/delete-user-profile-image/{userId}`           | Delete profile image                              |


---

## API Details

### 1. Force Update Version

**Endpoint:** `GET /api/configurations/force-update-version?device_type={ios|android}`

**Authentication:** Required

**Query Parameters:**

- `device_type` (required) - "ios" or "android"

**Response:**

```json
{
    "status": "success",
    "data": {
        "version": "1.2.0"
    }
}
```

**Implementation:**

- Call on app startup before showing main screen
- Compare with current app version
- If current < required: show force update screen and block app
- Cache response for 5-10 minutes

---

### 2. Login

**Endpoint:** `POST /api/login`

**Authentication:** Not required

**Request Body:**

```json
{
    "email": "driver@example.com",
    "password": "password123",
    "type": "driver"
}
```

**Response:**

```json
{
    "status": "success",
    "data": {
        "user": {
            "id": 1,
            "name": "John Doe",
            "email": "driver@example.com"
        },
        "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
    }
}
```

**Implementation:**

- Store token securely after successful login
- Call Save Device Token API (#3) after login

---

### 3. Save Device Token

**Endpoint:** `POST /api/mobile/save-device-token`

**Authentication:** Required

**Request Body:**

```json
{
    "device_token": "fcm-token-or-apns-token",
    "device_type": "android",
    "device_id": "optional-device-id"
}
```

**Parameters:**

- `device_token` (required) - FCM token (Android) or APNS token (iOS)
- `device_type` (required) - "android" or "ios"
- `device_id` (optional) - Unique device identifier

**Response:**

```json
{
    "status": "success",
    "message": "Device token saved successfully"
}
```

**Implementation:**

- Call after successful login
- Call when device token changes
- Request notification permissions first
- Retry if API call fails
- App must call OneSignal.login(user_id) so backend can send push via external_id

---

### 4. Forgot Password (Web)

**Endpoint:** `POST /api/forgot-password`

**Authentication:** Not required

**Request Body:**

```json
{
    "email": "driver@example.com",
    "type": "driver"
}
```

**Response:**

```json
{
    "status": "success",
    "message": "Password reset link has been sent to your email."
}
```

---

### 4a. Mobile Forgot Password (Request/Resend OTP)

**Endpoint:** `POST /api/mobile/forgot-password`

**Authentication:** Not required

**Description:** Request a 6-digit OTP code to be sent to the user's email for password reset. This endpoint can also be called again to resend a new OTP if the user didn't receive the original email. This is the first step in the mobile app password reset flow.

**Request Body:**

```json
{
    "email": "driver@example.com",
    "type": "driver"
}
```

**Parameters:**

- `email` (required) - User's email address
- `type` (required) - User role, must be "driver" for driver app

**Response (Success):**

```json
{
    "message": "OTP code has been sent to your email."
}
```

**Response (Rate Limit Exceeded):**

```json
{
    "message": "Too many OTP requests. Please try again later."
}
```

**Response (Too Soon - for resend):**

```json
{
    "message": "Please wait 45 second(s) before requesting a new OTP."
}
```

**Response (Resend Success):**

```json
{
    "message": "A new OTP code has been sent to your email."
}
```

**Rate Limiting:**

- Maximum 3 requests per email per hour
- Maximum 3 requests per email per 15 minutes
- Minimum 60 seconds between requests (prevents spam/resend abuse)
- Rate limiting is per email address (not just IP)

**Security Features:**

- Email enumeration protection (always returns success message)
- Previous unverified OTPs are invalidated when new one is sent
- OTP expires after 10 minutes
- OTP is never "000000" (weak code prevention)
- Minimum interval prevents rapid-fire resends

**Implementation:**

- **First Request:** Call this endpoint when user taps "Forgot Password"
- **Resend:** Call the same endpoint again if email not received (after 60 seconds)
- Show success message to user
- Display countdown timer (10 minutes) for OTP expiration
- Check user's email for 6-digit OTP code
- Show "Resend OTP" button after 60 seconds (calls same endpoint)
- Disable resend button and show countdown if too soon

**Error Handling:**

- `400` - Rate limit exceeded or too soon (show appropriate message)
- `422` - Validation error (check email format, type value)
- `500` - Server error (show generic error, allow retry)

---

### 4b. Verify OTP

**Endpoint:** `POST /api/mobile/verify-otp`

**Authentication:** Not required

**Description:** Verify the 6-digit OTP code received via email. This must be called before resetting the password.

**Request Body:**

```json
{
    "email": "driver@example.com",
    "type": "driver",
    "otp": "123456"
}
```

**Parameters:**

- `email` (required) - User's email address
- `type` (required) - User role, must be "driver" for driver app
- `otp` (required) - 6-digit OTP code from email

**Response (Success):**

```json
{
    "message": "OTP verified successfully."
}
```

**Response (Invalid OTP):**

```json
{
    "message": "Invalid or expired OTP code."
}
```

**Response (OTP Locked):**

```json
{
    "message": "Too many failed attempts. Please try again in 12 minute(s)."
}
```

**Response (Expired OTP):**

```json
{
    "message": "OTP code has expired. Please request a new one."
}
```

**Rate Limiting:**

- Maximum 5 verification attempts per email per 15 minutes
- Rate limiting is per email address

**Security Features:**

- Maximum 5 failed attempts before 15-minute lockout
- OTP expires after 10 minutes
- Timing attack protection (constant-time comparison)
- Failed attempts are tracked and logged

**Implementation:**

- Call this endpoint when user enters OTP code
- Show loading state during verification
- On success: Enable "Reset Password" button
- On failure: Show error message, increment attempt counter
- After 5 failed attempts: Show lockout message with countdown
- If OTP expired: Show message to request new OTP

**Error Handling:**

- `400` - Invalid/expired OTP or locked (show specific message)
- `422` - Validation error (OTP format)
- `429` - Rate limit exceeded (too many attempts)
- `500` - Server error

**Business Rules:**

- OTP must be verified before password reset
- Verified OTP is valid for 30 minutes for password reset
- Only the latest unverified OTP can be verified
- Previous OTPs are automatically invalidated

---

### 4c. Reset Password

**Endpoint:** `POST /api/mobile/reset-password`

**Authentication:** Not required

**Description:** Reset the user's password after OTP verification. This is the final step in the password reset flow.

**Request Body:**

```json
{
    "email": "driver@example.com",
    "type": "driver",
    "otp": "123456",
    "password": "newpassword123",
    "password_confirmation": "newpassword123"
}
```

**Parameters:**

- `email` (required) - User's email address
- `type` (required) - User role, must be "driver" for driver app
- `otp` (required) - Verified 6-digit OTP code
- `password` (required) - New password (minimum 8 characters)
- `password_confirmation` (required) - Must match password

**Response (Success):**

```json
{
    "message": "Password has been reset successfully."
}
```

**Response (Invalid OTP):**

```json
{
    "message": "Invalid or expired OTP code. Please verify the OTP first or request a new one."
}
```

**Response (Same Password):**

```json
{
    "message": "New password must be different from your current password."
}
```

**Response (Validation Error):**

```json
{
    "message": "Validation failed.",
    "errors": {
        "password": ["The password must be at least 8 characters."],
        "password_confirmation": ["The password confirmation does not match."]
    }
}
```

**Rate Limiting:**

- Same as Verify OTP API (#4b)
- Maximum 5 attempts per email per 15 minutes

**Security Features:**

- Requires verified OTP (must call Verify OTP first)
- Verified OTP must be used within 30 minutes
- Password must be different from current password
- OTP is deleted after successful password reset
- All OTPs for email/role are cleaned up after reset

**Implementation:**

- Call this endpoint after successful OTP verification
- Show password strength indicator
- Validate password match before submission
- On success: Show success message, redirect to login
- On failure: Show specific error message
- Clear OTP from local storage after success

**Error Handling:**

- `400` - Invalid/expired OTP or same password (show specific message)
- `422` - Validation error (password requirements, confirmation mismatch)
- `429` - Rate limit exceeded
- `500` - Server error

**Password Requirements:**

- Minimum 8 characters
- Must match password_confirmation
- Must be different from current password

**Business Rules:**

- OTP must be verified first (call Verify OTP API)
- Verified OTP is valid for 30 minutes
- Only one password reset per OTP
- OTP is single-use (deleted after reset)

**Complete Flow Example:**

1. User taps "Forgot Password" → Call API #4a
2. User receives email with OTP code
3. User enters OTP → Call API #4c
4. OTP verified successfully
5. User enters new password → Call API #4d
6. Password reset successful → Redirect to login

---

### 5. Get User Details

**Endpoint:** `GET /api/get-user-details`

**Authentication:** Required

**Response:**

```json
{
    "status": "success",
    "data": {
        "id": 1,
        "name": "John Doe",
        "email": "driver@example.com",
        "phone": "+1234567890",
        "street": "123 Main St",
        "city": "New York",
        "state": "NY",
        "country": "USA",
        "image_url": "https://example.com/profile.jpg",
        "locations": [
            {
                "id": 1,
                "name": "Warehouse A"
            }
        ]
    }
}
```

**Implementation:**

- Call after login to get user info
- Use for settings screen pre-population

---

### 6. Get Schedules

**Endpoint:** `GET /api/schedules`

**Authentication:** Required

**Query Parameters:**

- `scheduleDate` (optional) - Date in "YYYY-MM-DD" format. Default: today
- `search` (optional) - Search query
- `hideCompletedJob` (optional) - Hide completed schedules. Default: false
- `page` (optional) - Page number. Default: 1
- `limit` (optional) - Items per page. Default: 10

**Response:**

```json
{
    "status": "success",
    "data": {
        "data": [
            {
                "id": 1,
                "invoice_number": "INV-001",
                "carrier_name": "ABC Logistics",
                "trailer_number": "TRL-123",
                "door_name": "Door 1",
                "in_time": null,
                "out_time": null,
                "completed_time": null,
                "parked_time": null,
                "comments": "",
                "location_id": 1
            }
        ],
        "pagination": {
            "current_page": 1,
            "last_page": 5,
            "per_page": 10,
            "total": 50
        }
    }
}
```

**Implementation:**

- Call on home screen load
- Update when filters change
- Implement pull-to-refresh
- Handle pagination

---

### 7. Get Available Trailers

**Endpoint:** `GET /api/get-all-available-trailers-list-for-location?isDriverTable=1`

**Authentication:** Required

**Response:**

```json
{
    "status": "success",
    "data": {
        "data": [
            {
                "id": "1",
                "name": "TRL-123",
                "carrier_id": "5"
            }
        ]
    }
}
```

**Implementation:**

- Call when showing trailer picker
- Filter by `carrier_id` for specific schedule
- Cache result to reduce API calls

---

### 8. Get Door List

**Endpoint:** `GET /api/get-all-door-list-for-schedule`

**Authentication:** Required

**Response:**

```json
{
    "status": "success",
    "data": {
        "data": [
            {
                "id": "1",
                "name": "Door 1"
            }
        ]
    }
}
```

**Implementation:**

- Call when showing door picker
- Cache result (doors don't change frequently)

---

### 9. Log Time

**Endpoint:** `POST /api/schedules/{id}/log-time`

**Authentication:** Required

**Description:** Unified endpoint for logging schedule times. Server generates time automatically in UTC.

**Request Body:**

**For "in" type:**

```json
{
    "type": "in"
}
```

**For "out" type:**

```json
{
    "type": "out"
}
```

**For "completed" type:**

```json
{
    "type": "completed"
}
```

**For "parked" type:**

```json
{
    "type": "parked",
    "latitude": 40.7128,
    "longitude": -74.006
}
```

**Parameters:**

- `type` (required) - "in", "out", "completed", or "parked"
- `latitude` (required for "parked") - GPS latitude
- `longitude` (required for "parked") - GPS longitude

**Response:**

```json
{
    "status": "success",
    "message": "Log in successfully.",
    "data": {
        "id": 1,
        "in_time": "09:00:00",
        "in_user_name": "John Doe"
    }
}
```

**Business Rules:**

- "in": Requires `location_id` and `door_id` assigned. Validates door not in use.
- "out": Requires `in_time` recorded
- "completed": Requires both `in_time` and `out_time`
- "parked": Requires `completed_time` and GPS coordinates

**Implementation:**

- Time is generated server-side - do not send time from client
- For "parked": Capture GPS location first, request permissions if needed
- Show confirmation dialogs before logging
- Update UI immediately after success

---

### 10. Update By Values

**Endpoint:** `POST /api/schedules/update-by-values/{id}`

**Authentication:** Required

**Description:** Update trailer, door, or comments. **Drivers cannot edit times** - times are generated by Log Time API (#9).

**Request Body:**

**Update trailer:**

```json
{
    "trailer_id": "123"
}
```

**Update door:**

```json
{
    "door_id": "456"
}
```

**Update comments:**

```json
{
    "comments": "Updated comments"
}
```

**Response:**

```json
{
    "status": "success",
    "message": "Schedule updated successfully."
}
```

**Implementation:**

- Only update fields before `in_time` is recorded
- Update local state immediately for better UX

---

### 10a. Offline Sync

**Endpoint:** `POST /api/schedules/offline-sync`

**Authentication:** Required (driver role only)

**Description:** Batch synchronization endpoint for schedule updates and log times when the driver comes back online. Use this instead of multiple individual calls to Log Time (#9) and Update By Values (#10) when syncing data collected offline. Supports conflict detection via `client_updated_at` timestamp.

**Rate Limiting:** 60 requests per minute per user (higher than standard API limits to accommodate batch sync)

**Request Body:**

```json
{
    "schedules": [
        {
            "id": 123,
            "client_updated_at": "2025-02-19T10:30:00Z",
            "trailer_id": "456",
            "door_id": 7,
            "comments": "Optional comment",
            "log_times": [
                { "type": "in", "local_timestamp": "2025-02-19T10:30:00" },
                { "type": "out", "local_timestamp": "2025-02-19T11:00:00" },
                { "type": "completed", "local_timestamp": "2025-02-19T11:30:00" },
                { "type": "parked", "local_timestamp": "2025-02-19T12:00:00", "latitude": 40.7128, "longitude": -74.006 }
            ]
        }
    ]
}
```

**Parameters:**

- `schedules` (required) - Array of schedule objects (max 10 per request)
- `schedules.*.id` (required) - Schedule ID
- `schedules.*.client_updated_at` (required) - ISO 8601 timestamp when client last modified this schedule (used for conflict detection)
- `schedules.*.trailer_id` (optional) - Trailer ID (string)
- `schedules.*.door_id` (optional) - Door ID (integer)
- `schedules.*.comments` (optional) - Comments (max 1000 chars)
- `schedules.*.log_times` (optional) - Array of log time entries
- `schedules.*.log_times.*.type` (required) - "in", "out", "completed", or "parked"
- `schedules.*.log_times.*.local_timestamp` (optional) - Client's local timestamp for the event (converted to UTC by server)
- `schedules.*.log_times.*.latitude` (required for "parked") - GPS latitude (-90 to 90)
- `schedules.*.log_times.*.longitude` (required for "parked") - GPS longitude (-180 to 180)

**Validation:** Each schedule must have at least one update field (`trailer_id`, `door_id`, `comments`) or a non-empty `log_times` array.

**Response (Success):**

```json
{
    "status": "success",
    "message": "Offline sync completed",
    "data": {
        "succeeded": [
            {
                "id": 123,
                "status": "updated",
                "updated_at": "2025-02-19T12:05:00.000000Z",
                "trailer_id": "456",
                "door_id": 7,
                "comments": "Optional comment",
                "log_times": {
                    "succeeded": [
                        { "type": "in", "in_time": "10:30:00", "in_user_name": "John Doe" },
                        { "type": "out", "out_time": "11:00:00", "out_user_name": "John Doe" }
                    ],
                    "failed": []
                },
                "schedule_status": "completed",
                "schedule": {}
            }
        ],
        "failed": [],
        "server_time": "2025-02-19T12:05:00.000000Z"
    }
}
```

**Response (Partial Success):** Some schedules may succeed while others fail. Check `succeeded` and `failed` arrays.

**Failed Item Error Codes:**

- `NOT_FOUND` - Schedule does not exist or driver has no access
- `CONFLICT` - Server has newer data; client's `client_updated_at` is older than server `updated_at` and values differ
- `UPDATE_NOT_ALLOWED` - Cannot update trailer/door after IN time is logged
- `TRAILER_REQUIRED` - Trailer must be selected before logging time
- `DOOR_REQUIRED` - Door must be selected before logging time
- `INVALID_ORDER` - Log times must be in order: IN → OUT → Completed → Parked
- `ALREADY_LOGGED` - Time type already recorded for this schedule
- `PREREQUISITE_MISSING` - Previous log time not yet recorded (e.g., OUT requires IN before it)
- `VALIDATION_ERROR` - Invalid trailer_id, door_id, or other validation failure

**Conflict Response (in `failed` array):**

```json
{
    "id": 123,
    "status": "conflict",
    "error": "Schedule was modified on server with different values",
    "error_code": "CONFLICT",
    "client_updated_at": "2025-02-19T10:30:00Z",
    "server_updated_at": "2025-02-19T11:00:00.000000Z",
    "server_data": {
        "trailer_id": "789",
        "door_id": 8,
        "comments": "Server comment",
        "in_time": "10:45:00",
        "out_time": null,
        "completed_time": null,
        "parked_time": null
    },
    "conflict_details": {
        "changed_fields": ["trailer_id", "door_id"],
        "server_values": {},
        "client_values": {}
    }
}
```

**Business Rules:**

- **Batch size:** Maximum 10 schedules per request. Split into multiple requests if needed.
- **Updates:** `trailer_id` and `door_id` can only be updated before IN time is logged. `comments` can always be updated.
- **Log time order:** IN → OUT → Completed → Parked (strict order enforced)
- **Conflict detection:** If server `updated_at` is newer than `client_updated_at` and field values differ, the update is rejected with `CONFLICT`. App should prompt user to resolve (e.g., show server data and let user choose).
- **Time handling:** Use `local_timestamp` to preserve driver's actual event time; server converts to UTC. If omitted, server uses current UTC time.

**Implementation:**

- Queue schedule changes locally when offline
- On connectivity restore, call this endpoint with batched changes (up to 10 per request)
- Process `failed` array: retry validation errors after user fix; show conflict UI for `CONFLICT`; skip `NOT_FOUND`
- Update local cache with `succeeded` results and `server_time`
- Use `server_time` to sync client clock if needed

---

### 11. Update User Details

**Endpoint:** `POST /api/update-user-details`

**Authentication:** Required

**Request Headers:** `Content-Type: multipart/form-data`

**Request Body (FormData):**

- `profile_image` (File, optional) - JPEG/PNG
- `phone` (required) - Phone number
- `password` (optional) - New password (only if changing)
- `name` (required) - Full name
- `email` (required) - Email
- `street` (required) - Street address
- `city` (required) - City
- `state` (required) - State
- `country` (required) - Country

**Response:**

```json
{
    "status": "success",
    "message": "Profile updated successfully",
    "data": {
        "id": 1,
        "name": "John Doe",
        "email": "driver@example.com",
        "phone": "+1234567890",
        "image_url": "https://example.com/profile.jpg"
    }
}
```

**Implementation:**

- Compress/resize image before upload (max 2MB recommended)
- Only include password if user wants to change it
- Show upload progress for image

---

### 12. Delete Profile Image

**Endpoint:** `DELETE /api/delete-user-profile-image/{userId}`

**Authentication:** Required

**Response:**

```json
{
    "status": "success",
    "message": "Profile image deleted successfully"
}
```

**Implementation:**

- Show confirmation dialog before deletion
- Refresh user data after success

---

## WebSocket Integration

The app uses WebSocket for real-time schedule updates. When schedules are created, updated, deleted, or reordered, connected drivers receive instant updates.

### Channel Subscription

**Channel Format:** `schedule.location.{locationId}`

- Get `locationId` from user details after login (API #5)
- Subscribe to channel: `schedule.location.{locationId}`
- **Important:** Drivers can only subscribe to their assigned location's channel

**Authentication:**

When subscribing to a private channel, call:

- **Endpoint:** `POST /api/broadcasting/auth`
- **Headers:** `Authorization: Bearer {token}`
- **Body:**
  ```json
  {
      "socket_id": "socket-id-from-websocket",
      "channel_name": "schedule.location.{locationId}"
  }
  ```
- **Response:** `{ "auth": "authentication-token" }`
- Use the `auth` token in your channel subscription

### Event Handling

**Event Name:** `schedule.event`

Listen for messages with `event: "schedule.event"` on your subscribed channel.

**Event Message Structure:**

```json
{
    "event": "schedule.event",
    "data": {
        "action": "created|updated|deleted|order_changed",
        "location_id": 1,
        "schedule": {
            // Full schedule object (for created/updated only)
            "id": 1,
            "invoice_number": "INV-001",
            "carrier_name": "ABC Logistics",
            "trailer_number": "TRL-123",
            "door_name": "Door 1",
            "in_time": "09:00:00",
            "out_time": null,
            "completed_time": null,
            "parked_time": null,
            "comments": "",
            "location_id": 1
        },
        "schedule_id": 1 // Only for deleted action
    }
}
```

**Event Actions:**

1. `**created`** - New schedule created
  - `data.schedule` contains full schedule object
  - **Action:** Add new schedule to your list
2. `**updated`** - Schedule updated
  - `data.schedule` contains full updated schedule object
  - **Action:** Update existing schedule in your list
3. `**deleted`** - Schedule deleted
  - `data.schedule_id` contains schedule ID
  - **Action:** Remove schedule from your list
4. `**order_changed`** - Display order changed
  - Only `action` and `location_id` in data
  - **Action:** Refetch entire schedule list from API (GET /api/schedules)

### Notes

- Subscribe after successful login when you have location ID
- Unsubscribe when leaving schedule screen
- Handle 401 errors by redirecting to login
- Handle 403 errors (user doesn't have access to location)

---

## Implementation Guidelines

### Error Handling

- Handle 401 errors by clearing token and redirecting to login
- Show user-friendly error messages
- Implement retry logic for failed requests
- Handle network errors gracefully

### Loading States

- Show loading indicators during API calls
- Disable buttons/forms while processing
- Use skeleton screens for better UX

### Data Caching

- Cache static data (doors, trailers) when possible
- Implement offline support for critical data (use Offline Sync API #10a for batch syncing schedule updates and log times when connectivity is restored)
- Refresh cache when data changes

### Time Handling

- All times from backend are in UTC format (HH:MM:SS)
- Convert to local time for display only
- Do not send times from client - server generates them (exception: Offline Sync API #10a accepts `local_timestamp` for events recorded offline)

### GPS/Location

- Request location permissions properly
- Use high accuracy GPS when available
- Handle GPS permission errors gracefully
- Required for "parked" type in Log Time API

### Push Notifications

- Request notification permissions before saving device token
- Update device token when it changes
- Handle token refresh scenarios

### Security

- Store tokens securely (Keychain/EncryptedSharedPreferences)
- Never log sensitive data (tokens, passwords)
- Use certificate pinning in production
- Encrypt sensitive local data

---

## Support

For API-related questions or issues:

- Contact the development team
- Refer to the backend API source code
- Check backend logs for detailed error messages

---

**Version 1.0** - Driver API Documentation for Mobile App Integration