**Prepared by:** Oditha

**Date:** 23 January 2026

**Version:** 1.0

**Reference:** [FRD - HoReCa Field Operations & Workflow Management](https://www.notion.so/FRD-HoReCa-Field-Operations-Workflow-Management-2f7cd2773bc548c9a2595d856f15ac15?pvs=21)

---

## Overview

This document provides the complete API specification for the **Lion HoReCa Excellence Mobile Application**. The API is built using **Laravel** and follows **RESTful** principles.

---

## API Architecture

### Base URL

-   **Production:** [`https://api.lionhoreca.com/v1`](https://api.lionhoreca.com/v1)
-   **Staging:** [`https://api-staging.lionhoreca.com/v1`](https://api-staging.lionhoreca.com/v1)
-   **Development:** [`http://localhost:8000/api/v1`](http://localhost:8000/api/v1)

### Technology Stack

-   **Framework:** Laravel 10+
-   **API Type:** RESTful JSON API
-   **Authentication:** Laravel Sanctum (Token-based)
-   **Rate Limiting:** 60 requests per minute per user
-   **Versioning:** URI versioning (/v1, /v2)

### Design Principles

-   RESTful conventions (GET, POST, PUT, PATCH, DELETE)
-   JSON request/response format
-   HTTP status codes for response status
-   Token-based authentication
-   Pagination for list endpoints
-   Error responses with consistent structure

---

## Authentication

### 1. Login

**Endpoint:** `POST /mobile/auth/login`

**Description:** Authenticate user and receive access token

**Request Headers:**

-   `Content-Type: application/json`
-   `Accept: application/json`

**Request Body:**

```json
{
    "email": "user@example.com",
    "password": "password123",
    "device_name": "iPhone 14 Pro"
}
```

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "token": "1|abcdefghijklmnopqrstuvwxyz",
        "token_type": "Bearer",
        "expires_at": "2026-02-23T19:20:58.848Z",
        "user": {
            "id": 123,
            "name": "John Doe",
            "email": "john.doe@example.com",
            "role": "lsr",
            "phone": "+94771234567",
            "avatar_url": "https://storage.example.com/avatars/123.jpg",
            "territory_id": 5,
            "region_id": 2
        }
    },
    "message": "Login successful"
}
```

**Error Response (401 Unauthorized):**

```json
{
    "success": false,
    "error": {
        "code": "INVALID_CREDENTIALS",
        "message": "Invalid email or password"
    }
}
```

---

### 2. Logout

**Endpoint:** `POST /mobile/auth/logout`

**Description:** Revoke current access token

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Success Response (200 OK):**

```json
{
    "success": true,
    "message": "Logged out successfully"
}
```

---

### 3. Refresh Token

**Endpoint:** `POST /mobile/auth/refresh-token`

**Description:** Refresh access token before expiry

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "token": "2|newtoken123456789",
        "token_type": "Bearer",
        "expires_at": "2026-02-24T19:20:58.848Z"
    }
}
```

---

## Outlets

### 4. Get Outlet List

**Endpoint:** `GET /mobile/outlets`

**Description:** Retrieve paginated list of assigned outlets with geolocation sorting

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Query Parameters:**

-   `page` (integer, optional): Page number (default: 1)
-   `per_page` (integer, optional): Items per page (default: 25, max: 100)
-   `latitude` (decimal, optional): User's current latitude
-   `longitude` (decimal, optional): User's current longitude
-   `search` (string, optional): Search by outlet name or address
-   `outlet_type` (string, optional): Filter by type (restaurant, hotel, cafe, bar)
-   `has_overdue_audit` (boolean, optional): Filter outlets with overdue audits
-   `has_pending_sr` (boolean, optional): Filter outlets with pending service requests
-   `unvisited` (boolean, optional): Filter outlets never visited
-   `sort_by` (string, optional): Sort field (distance, name, last_visit)
-   `sort_order` (string, optional): asc or desc

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "outlets": [
            {
                "id": 101,
                "name": "ABC Restaurant",
                "address": "123 Main St, Colombo 03",
                "latitude": 6.927079,
                "longitude": 79.861244,
                "outlet_type": "restaurant",
                "contact_phone": "+94112345678",
                "distance_km": 1.2,
                "last_visit": {
                    "date": "2026-01-20T10:30:00Z",
                    "days_ago": 3
                },
                "status_indicators": {
                    "has_overdue_audit": false,
                    "has_pending_sr": true,
                    "pending_sr_count": 2
                },
                "assigned_template": {
                    "id": 5,
                    "name": "Restaurant Standard"
                }
            }
        ],
        "pagination": {
            "current_page": 1,
            "per_page": 25,
            "total": 142,
            "total_pages": 6,
            "has_more": true
        }
    }
}
```

---

### 5. Get Outlet Details

**Endpoint:** `GET /mobile/outlets/{id}`

**Description:** Retrieve detailed information for a specific outlet

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): Outlet ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "outlet": {
            "id": 101,
            "name": "ABC Restaurant",
            "address": "123 Main St, Colombo 03",
            "latitude": 6.927079,
            "longitude": 79.861244,
            "outlet_type": "restaurant",
            "contact_phone": "+94112345678",
            "contact_email": "info@abcrestaurant.lk",
            "territory": {
                "id": 5,
                "name": "Colombo Central"
            },
            "region": {
                "id": 2,
                "name": "Western Province"
            },
            "assigned_users": {
                "lsr": {
                    "id": 123,
                    "name": "John Doe"
                },
                "tm": {
                    "id": 45,
                    "name": "Jane Smith"
                },
                "sm": {
                    "id": 12,
                    "name": "Bob Manager"
                }
            },
            "workflow_template": {
                "id": 5,
                "name": "Restaurant Standard",
                "workflows": [
                    {
                        "id": 1,
                        "name": "Impulse Workflow",
                        "is_enabled": true
                    },
                    {
                        "id": 2,
                        "name": "Cooler Workflow",
                        "is_enabled": false
                    }
                ]
            },
            "brands": {
                "must_have": [
                    { "id": 1, "name": "Lion Lager" },
                    { "id": 2, "name": "Lion Stout" }
                ],
                "optional": [{ "id": 3, "name": "Carlsberg" }]
            },
            "equipment": [
                {
                    "type": "cooler",
                    "name": "300L Cooler",
                    "quantity": 2
                }
            ],
            "last_visit": {
                "date": "2026-01-20T10:30:00Z",
                "user": "John Doe",
                "time_spent_minutes": 45,
                "workflows_completed": 3
            }
        }
    }
}
```

---

### 6. Get Outlet Workflows

**Endpoint:** `GET /mobile/outlets/{id}/workflows`

**Description:** Retrieve workflows assigned to an outlet

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): Outlet ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "workflows": [
            {
                "id": 1,
                "name": "Impulse Workflow",
                "description": "Check impulse display presence",
                "category": "impulse",
                "icon": "⚡",
                "color": "#3498DB",
                "steps_count": 8,
                "is_enabled": true,
                "execution_status": {
                    "status": "in_progress",
                    "completed_steps": 3,
                    "total_steps": 8,
                    "last_execution_id": 456,
                    "last_execution_date": "2026-01-23T14:00:00Z"
                }
            }
        ]
    }
}
```

---

## Check-in/Check-out

### 7. Check-in to Outlet

**Endpoint:** `POST /mobile/outlets/{id}/check-in`

**Description:** Record check-in at outlet location

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Path Parameters:**

-   `id` (integer, required): Outlet ID

**Request Body:**

```json
{
    "latitude": 6.927079,
    "longitude": 79.861244,
    "purpose": "routine_visit",
    "remote_checkin_reason": "Outlet location marker is incorrect"
}
```

**Success Response (201 Created):**

```json
{
    "success": true,
    "data": {
        "visit": {
            "id": 789,
            "outlet_id": 101,
            "check_in_time": "2026-01-23T10:00:00Z",
            "distance_from_outlet": 25.5,
            "within_geofence": true
        }
    },
    "message": "Checked in successfully"
}
```

**Validation Errors (422 Unprocessable Entity):**

```json
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Validation failed",
        "details": {
            "latitude": ["The latitude field is required"],
            "remote_checkin_reason": [
                "Reason is required when checking in outside geofence"
            ]
        }
    }
}
```

---

### 8. Get Visit Details

**Endpoint:** `GET /mobile/visits/{id}`

**Description:** Retrieve visit details

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): Visit ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "visit": {
            "id": 789,
            "outlet": {
                "id": 101,
                "name": "ABC Restaurant"
            },
            "user": {
                "id": 123,
                "name": "John Doe"
            },
            "check_in_time": "2026-01-23T10:00:00Z",
            "check_out_time": null,
            "time_spent_minutes": null,
            "is_active": true,
            "workflows_executed": [
                {
                    "id": 456,
                    "workflow_name": "Impulse Workflow",
                    "status": "in_progress"
                }
            ]
        }
    }
}
```

---

### 9. Check-out from Outlet

**Endpoint:** `POST /mobile/visits/{id}/check-out`

**Description:** Record check-out and visit outcome

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Path Parameters:**

-   `id` (integer, required): Visit ID

**Request Body:**

```json
{
    "visit_outcome": "completed",
    "outcome_reason": null
}
```

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "visit": {
            "id": 789,
            "check_in_time": "2026-01-23T10:00:00Z",
            "check_out_time": "2026-01-23T11:30:00Z",
            "time_spent_minutes": 90,
            "visit_outcome": "completed"
        }
    },
    "message": "Checked out successfully"
}
```

---

### 10. Get Visit History

**Endpoint:** `GET /mobile/visits/history`

**Description:** Retrieve paginated visit history

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Query Parameters:**

-   `page` (integer, optional): Page number
-   `per_page` (integer, optional): Items per page
-   `outlet_id` (integer, optional): Filter by outlet
-   `date_from` (date, optional): Start date (YYYY-MM-DD)
-   `date_to` (date, optional): End date (YYYY-MM-DD)

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "visits": [
            {
                "id": 789,
                "outlet_name": "ABC Restaurant",
                "check_in_time": "2026-01-23T10:00:00Z",
                "check_out_time": "2026-01-23T11:30:00Z",
                "time_spent_minutes": 90,
                "workflows_completed": 3,
                "visit_outcome": "completed"
            }
        ],
        "pagination": {
            "current_page": 1,
            "total": 45,
            "has_more": true
        }
    }
}
```

---

## Workflows

### 11. Get Workflow Details

**Endpoint:** `GET /mobile/workflows/{id}`

**Description:** Retrieve workflow configuration with steps

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): Workflow ID

**Query Parameters:**

-   `outlet_id` (integer, optional): Apply outlet-specific customizations

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "workflow": {
            "id": 1,
            "name": "Impulse Workflow",
            "description": "Check impulse display presence",
            "category": "impulse",
            "steps": [
                {
                    "id": 10,
                    "step_order": 1,
                    "name": "Is impulse display present?",
                    "description": "Check if Lion impulse display is visible at counter",
                    "question_type": "selection",
                    "is_mandatory": true,
                    "allow_skip": false,
                    "allow_remarks": true,
                    "require_photo": true,
                    "photo_count": 2,
                    "sample_photo_url": "https://storage.example.com/samples/impulse-display.jpg",
                    "instructions": "Take photo from customer viewpoint",
                    "options": [
                        {
                            "id": 100,
                            "option_text": "Yes",
                            "option_value": "yes"
                        },
                        {
                            "id": 101,
                            "option_text": "No",
                            "option_value": "no",
                            "triggers_service_request": true
                        }
                    ],
                    "conditions": []
                },
                {
                    "id": 11,
                    "step_order": 2,
                    "name": "Display condition",
                    "conditions": [
                        {
                            "condition_step_id": 10,
                            "condition_operator": "equals",
                            "condition_value": "yes"
                        }
                    ]
                }
            ]
        }
    }
}
```

---

## Workflow Execution

### 12. Start Workflow Execution

**Endpoint:** `POST /mobile/workflows/{id}/start`

**Description:** Begin a new workflow execution

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Path Parameters:**

-   `id` (integer, required): Workflow ID

**Request Body:**

```json
{
    "visit_id": 789,
    "outlet_id": 101
}
```

**Success Response (201 Created):**

```json
{
    "success": true,
    "data": {
        "execution": {
            "id": 456,
            "workflow_id": 1,
            "visit_id": 789,
            "outlet_id": 101,
            "status": "in_progress",
            "started_at": "2026-01-23T10:15:00Z",
            "total_steps": 8,
            "completed_steps": 0
        }
    }
}
```

---

### 13. Get Execution Details

**Endpoint:** `GET /mobile/executions/{id}`

**Description:** Retrieve execution progress and responses

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): Execution ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "execution": {
            "id": 456,
            "workflow_id": 1,
            "workflow_name": "Impulse Workflow",
            "status": "in_progress",
            "started_at": "2026-01-23T10:15:00Z",
            "completed_at": null,
            "total_steps": 8,
            "completed_steps": 3,
            "responses": [
                {
                    "step_id": 10,
                    "response_value": "yes",
                    "response_text": null,
                    "remarks": "Display is prominent",
                    "photo_urls": [
                        "https://storage.example.com/photos/photo1.jpg",
                        "https://storage.example.com/photos/photo2.jpg"
                    ]
                }
            ]
        }
    }
}
```

---

### 14. Submit Step Response

**Endpoint:** `POST /mobile/executions/{id}/step-response`

**Description:** Submit response for a workflow step

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Path Parameters:**

-   `id` (integer, required): Execution ID

**Request Body:**

```json
{
    "step_id": 10,
    "response_value": "yes",
    "response_text": null,
    "remarks": "Display is prominent",
    "is_skipped": false,
    "skip_reason": null,
    "photo_urls": [
        "https://storage.example.com/photos/photo1.jpg",
        "https://storage.example.com/photos/photo2.jpg"
    ]
}
```

**Success Response (201 Created):**

```json
{
    "success": true,
    "data": {
        "response": {
            "id": 1001,
            "step_id": 10,
            "response_value": "yes",
            "created_at": "2026-01-23T10:20:00Z"
        },
        "service_request_triggered": false
    },
    "message": "Step response recorded"
}
```

**With Service Request Trigger:**

```json
{
    "success": true,
    "data": {
        "response": {
            "id": 1002,
            "step_id": 11,
            "response_value": "no"
        },
        "service_request_triggered": true,
        "service_request": {
            "id": 567,
            "sr_number": "SR-00567",
            "title": "Cooler Repair Request",
            "category": "Equipment Repair"
        }
    },
    "message": "Step response recorded and service request created"
}
```

---

### 15. Complete Workflow

**Endpoint:** `POST /mobile/executions/{id}/complete`

**Description:** Mark workflow execution as complete

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Path Parameters:**

-   `id` (integer, required): Execution ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "execution": {
            "id": 456,
            "status": "completed",
            "started_at": "2026-01-23T10:15:00Z",
            "completed_at": "2026-01-23T10:45:00Z",
            "time_taken_minutes": 30
        }
    },
    "message": "Workflow completed successfully"
}
```

---

### 16. Get Next Step

**Endpoint:** `GET /mobile/executions/{id}/next-step`

**Description:** Get next step considering conditional logic

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): Execution ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "next_step": {
            "id": 12,
            "step_order": 4,
            "name": "Brand availability",
            "is_visible": true
        },
        "progress": {
            "completed_steps": 3,
            "total_visible_steps": 6,
            "percentage": 50
        }
    }
}
```

**No More Steps (200 OK):**

```json
{
    "success": true,
    "data": {
        "next_step": null,
        "progress": {
            "completed_steps": 8,
            "total_visible_steps": 8,
            "percentage": 100
        }
    },
    "message": "All steps completed"
}
```

---

### 17. Get Execution History

**Endpoint:** `GET /mobile/executions/history`

**Description:** Retrieve past workflow executions

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Query Parameters:**

-   `page` (integer, optional): Page number
-   `per_page` (integer, optional): Items per page
-   `outlet_id` (integer, optional): Filter by outlet
-   `workflow_id` (integer, optional): Filter by workflow
-   `status` (string, optional): Filter by status (in_progress, completed, abandoned)

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "executions": [
            {
                "id": 456,
                "workflow_name": "Impulse Workflow",
                "outlet_name": "ABC Restaurant",
                "status": "completed",
                "started_at": "2026-01-23T10:15:00Z",
                "completed_at": "2026-01-23T10:45:00Z",
                "completed_steps": 8,
                "total_steps": 8
            }
        ],
        "pagination": {
            "current_page": 1,
            "total": 124,
            "has_more": true
        }
    }
}
```

---

## POSM Audits

### 18. Get My Audits

**Endpoint:** `GET /mobile/audits/my-audits`

**Description:** Retrieve audits assigned to current user (TM only)

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Query Parameters:**

-   `page` (integer, optional): Page number
-   `per_page` (integer, optional): Items per page
-   `status` (string, optional): Filter by status (scheduled, in_progress, completed)
-   `overdue_only` (boolean, optional): Show only overdue audits

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "audits": [
            {
                "id": 234,
                "outlet": {
                    "id": 101,
                    "name": "ABC Restaurant",
                    "outlet_type": "restaurant"
                },
                "scheduled_date": "2026-01-25",
                "due_date": "2026-01-30",
                "status": "scheduled",
                "is_overdue": false,
                "days_until_due": 7
            }
        ],
        "pagination": {
            "current_page": 1,
            "total": 15,
            "has_more": false
        }
    }
}
```

---

### 19. Get Audit Details

**Endpoint:** `GET /mobile/audits/{id}`

**Description:** Retrieve audit details and norms

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): Audit ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "audit": {
            "id": 234,
            "outlet": {
                "id": 101,
                "name": "ABC Restaurant",
                "outlet_type": "restaurant"
            },
            "scheduled_date": "2026-01-25",
            "due_date": "2026-01-30",
            "status": "scheduled",
            "norms": [
                {
                    "material_name": "Lion Poster A1",
                    "material_category": "branding",
                    "standard_quantity": 2,
                    "actual_quantity": null,
                    "variance": null
                },
                {
                    "material_name": "300L Cooler",
                    "material_category": "cooler",
                    "standard_quantity": 1,
                    "actual_quantity": null,
                    "variance": null
                }
            ]
        }
    }
}
```

---

### 20. Execute Audit

**Endpoint:** `POST /mobile/audits/{id}/execute`

**Description:** Submit POSM audit data

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Path Parameters:**

-   `id` (integer, required): Audit ID

**Request Body:**

```json
{
    "items": [
        {
            "material_name": "Lion Poster A1",
            "norm_quantity": 2,
            "actual_quantity": 2,
            "variance": 0,
            "remarks": null,
            "needs_restocking": false
        },
        {
            "material_name": "300L Cooler",
            "norm_quantity": 1,
            "actual_quantity": 0,
            "variance": -1,
            "remarks": "Cooler removed for repair",
            "needs_restocking": true
        }
    ]
}
```

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "audit": {
            "id": 234,
            "status": "in_progress",
            "items_submitted": 2
        }
    },
    "message": "Audit data saved"
}
```

---

### 21. Complete Audit

**Endpoint:** `POST /mobile/audits/{id}/complete`

**Description:** Mark audit as complete and trigger next audit

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Path Parameters:**

-   `id` (integer, required): Audit ID

**Request Body:**

```json
{
    "schedule_next_audit": true
}
```

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "audit": {
            "id": 234,
            "status": "completed",
            "completed_date": "2026-01-23"
        },
        "next_audit": {
            "id": 235,
            "scheduled_date": "2026-02-12",
            "due_date": "2026-02-17"
        }
    },
    "message": "Audit completed and next audit scheduled"
}
```

---

## Service Requests

### 22. Get My Service Requests

**Endpoint:** `GET /mobile/service-requests`

**Description:** Retrieve service requests (created by or assigned to user)

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Query Parameters:**

-   `page` (integer, optional): Page number
-   `per_page` (integer, optional): Items per page
-   `filter` (string, optional): all, my_requests, assigned_to_me
-   `status` (string, optional): open, in_progress, resolved, closed, cancelled
-   `priority` (string, optional): low, medium, high, critical
-   `overdue_only` (boolean, optional): Show only overdue SRs

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "service_requests": [
            {
                "id": 567,
                "sr_number": "SR-00567",
                "title": "Cooler Repair Request",
                "description": "Cooler reported as non-functional",
                "category": {
                    "id": 3,
                    "name": "Equipment Repair"
                },
                "outlet": {
                    "id": 101,
                    "name": "ABC Restaurant"
                },
                "status": "open",
                "priority": "high",
                "created_by": {
                    "id": 123,
                    "name": "John Doe"
                },
                "assigned_to": {
                    "id": 45,
                    "name": "Jane Smith"
                },
                "sla_due_date": "2026-01-25T10:00:00Z",
                "sla_status": "within_sla",
                "hours_until_sla": 36,
                "created_at": "2026-01-23T10:00:00Z"
            }
        ],
        "pagination": {
            "current_page": 1,
            "total": 23,
            "has_more": true
        }
    }
}
```

---

### 23. Get Service Request Details

**Endpoint:** `GET /mobile/service-requests/{id}`

**Description:** Retrieve detailed SR information

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): Service Request ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "service_request": {
            "id": 567,
            "sr_number": "SR-00567",
            "title": "Cooler Repair Request",
            "description": "Cooler reported as non-functional at ABC Restaurant during Cooler Workflow execution.",
            "category": {
                "id": 3,
                "name": "Equipment Repair"
            },
            "outlet": {
                "id": 101,
                "name": "ABC Restaurant",
                "address": "123 Main St, Colombo 03"
            },
            "workflow_context": {
                "workflow_id": 2,
                "workflow_name": "Cooler Workflow",
                "step_id": 5,
                "step_name": "Is cooler functional?",
                "response": "No"
            },
            "status": "open",
            "priority": "high",
            "created_by": {
                "id": 123,
                "name": "John Doe",
                "role": "lsr"
            },
            "assigned_to": {
                "id": 45,
                "name": "Jane Smith",
                "role": "tm"
            },
            "sla_due_date": "2026-01-25T10:00:00Z",
            "created_at": "2026-01-23T10:00:00Z",
            "resolved_date": null,
            "closed_date": null,
            "activity_log": [
                {
                    "id": 1001,
                    "user": {
                        "id": 123,
                        "name": "John Doe"
                    },
                    "action_type": "status_change",
                    "old_value": null,
                    "new_value": "open",
                    "comment": "Service request created",
                    "created_at": "2026-01-23T10:00:00Z"
                }
            ]
        }
    }
}
```

---

### 24. Update Service Request Status

**Endpoint:** `POST /mobile/service-requests/{id}/update-status`

**Description:** Change SR status

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Path Parameters:**

-   `id` (integer, required): Service Request ID

**Request Body:**

```json
{
    "status": "in_progress",
    "comment": "Started working on cooler repair"
}
```

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "service_request": {
            "id": 567,
            "status": "in_progress",
            "updated_at": "2026-01-23T11:00:00Z"
        }
    },
    "message": "Status updated successfully"
}
```

---

## File Upload

### 25. Upload File

**Endpoint:** `POST /mobile/files/upload`

**Description:** Upload photos and attachments

**Request Headers:**

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

**Request Body (Form Data):**

-   `file` (file, required): File to upload
-   `entity_type` (string, optional): Entity type (workflow_response, service_request)
-   `entity_id` (integer, optional): Entity ID

**Success Response (201 Created):**

```json
{
    "success": true,
    "data": {
        "file": {
            "id": 7890,
            "file_name": "photo_20260123_100000.jpg",
            "file_url": "https://storage.example.com/photos/7890.jpg",
            "file_type": "image/jpeg",
            "file_size": 2048576,
            "uploaded_at": "2026-01-23T10:00:00Z"
        }
    },
    "message": "File uploaded successfully"
}
```

**Validation Errors (422 Unprocessable Entity):**

```json
{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "File validation failed",
        "details": {
            "file": [
                "File size must not exceed 10MB",
                "File type must be: jpg, jpeg, png, pdf"
            ]
        }
    }
}
```

---

### 26. Get File URL

**Endpoint:** `GET /mobile/files/{id}`

**Description:** Retrieve file URL

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Path Parameters:**

-   `id` (integer, required): File ID

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "file": {
            "id": 7890,
            "file_url": "https://storage.example.com/photos/7890.jpg",
            "file_type": "image/jpeg",
            "file_size": 2048576
        }
    }
}
```

---

## Sync

### 27. Bulk Sync Offline Data

**Endpoint:** `POST /mobile/sync`

**Description:** Upload multiple offline records in bulk

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Content-Type: application/json`

**Request Body:**

```json
{
    "visits": [
        {
            "temp_id": "visit_local_001",
            "outlet_id": 101,
            "check_in_time": "2026-01-22T14:00:00Z",
            "check_in_lat": 6.927079,
            "check_in_lng": 79.861244,
            "check_out_time": "2026-01-22T15:30:00Z",
            "time_spent_minutes": 90,
            "visit_outcome": "completed"
        }
    ],
    "workflow_executions": [
        {
            "temp_id": "execution_local_001",
            "visit_temp_id": "visit_local_001",
            "workflow_id": 1,
            "outlet_id": 101,
            "started_at": "2026-01-22T14:05:00Z",
            "completed_at": "2026-01-22T14:30:00Z",
            "status": "completed",
            "responses": [
                {
                    "step_id": 10,
                    "response_value": "yes",
                    "remarks": "All good",
                    "photo_urls": [
                        "https://storage.example.com/photos/7890.jpg"
                    ]
                }
            ]
        }
    ],
    "service_requests": []
}
```

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "synced": {
            "visits": 1,
            "workflow_executions": 1,
            "service_requests": 0
        },
        "mapping": {
            "visits": {
                "visit_local_001": 789
            },
            "workflow_executions": {
                "execution_local_001": 456
            }
        },
        "failed": []
    },
    "message": "Sync completed successfully"
}
```

**Partial Success (200 OK):**

```json
{
    "success": true,
    "data": {
        "synced": {
            "visits": 1,
            "workflow_executions": 0,
            "service_requests": 0
        },
        "failed": [
            {
                "temp_id": "execution_local_001",
                "type": "workflow_execution",
                "error": "Visit ID not found"
            }
        ]
    },
    "message": "Sync partially completed with errors"
}
```

---

### 28. Get Sync Status

**Endpoint:** `GET /mobile/sync/status`

**Description:** Check sync status and pending items

**Request Headers:**

-   `Authorization: Bearer {token}`
-   `Accept: application/json`

**Success Response (200 OK):**

```json
{
    "success": true,
    "data": {
        "sync_status": {
            "last_sync_at": "2026-01-23T09:00:00Z",
            "is_syncing": false,
            "pending_items": {
                "visits": 0,
                "workflow_executions": 0,
                "service_requests": 0,
                "photos": 0
            }
        }
    }
}
```

---

## Error Responses

### Standard Error Format

All error responses follow this structure:

```json
{
    "success": false,
    "error": {
        "code": "ERROR_CODE",
        "message": "Human-readable error message",
        "details": {}
    }
}
```

### Common HTTP Status Codes

-   **200 OK:** Request successful
-   **201 Created:** Resource created successfully
-   **400 Bad Request:** Invalid request format
-   **401 Unauthorized:** Missing or invalid authentication token
-   **403 Forbidden:** User lacks permission for this resource
-   **404 Not Found:** Resource not found
-   **422 Unprocessable Entity:** Validation errors
-   **429 Too Many Requests:** Rate limit exceeded
-   **500 Internal Server Error:** Server error

### Common Error Codes

-   `INVALID_CREDENTIALS`: Login failed
-   `UNAUTHORIZED`: Missing or invalid token
-   `FORBIDDEN`: Insufficient permissions
-   `NOT_FOUND`: Resource not found
-   `VALIDATION_ERROR`: Input validation failed
-   `RATE_LIMIT_EXCEEDED`: Too many requests
-   `SERVER_ERROR`: Internal server error
-   `ALREADY_CHECKED_IN`: User already checked in to outlet
-   `NOT_CHECKED_IN`: Must check in before performing action
-   `WORKFLOW_NOT_FOUND`: Workflow does not exist
-   `STEP_NOT_FOUND`: Step does not exist
-   `INVALID_STEP_ORDER`: Steps must be completed in order
-   `MANDATORY_STEP_INCOMPLETE`: Mandatory step not completed
-   `SLA_BREACHED`: Service request SLA exceeded

---

## Rate Limiting

### Limits

-   **Per User:** 60 requests per minute
-   **Per Endpoint:** Varies (higher for read operations)

### Headers

Response headers include rate limit information:

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1706025658
```

### Rate Limit Exceeded Response (429 Too Many Requests):

```json
{
    "success": false,
    "error": {
        "code": "RATE_LIMIT_EXCEEDED",
        "message": "Too many requests. Please try again later.",
        "details": {
            "retry_after": 30
        }
    }
}
```

---

## Pagination

### Standard Pagination Format

All list endpoints return paginated results:

```json
{
    "success": true,
    "data": {
        "items": [],
        "pagination": {
            "current_page": 1,
            "per_page": 25,
            "total": 142,
            "total_pages": 6,
            "has_more": true
        }
    }
}
```

### Query Parameters

-   `page` (integer): Page number (default: 1)
-   `per_page` (integer): Items per page (default: 25, max: 100)

---

## Filtering & Sorting

### Common Filters

-   `search` (string): Full-text search
-   `status` (string): Filter by status
-   `date_from` (date): Start date (YYYY-MM-DD)
-   `date_to` (date): End date (YYYY-MM-DD)

### Common Sort Options

-   `sort_by` (string): Field to sort by
-   `sort_order` (string): `asc` or `desc`

---

## Webhooks (Future)

_Webhooks for real-time notifications are planned for Phase 02_

---

## Versioning

### API Version

-   Current version: **v1**
-   Versioned via URI: `/api/v1/`

### Breaking Changes

-   Major version changes for breaking changes
-   Minimum 6 months support for deprecated versions
-   Deprecation warnings in response headers

---

**Document Status:** Final

**Next Steps:** Share with mobile development team for implementation
