# Provider API Reference

> Base URL: `{{base_url}}/api/v1/provider`  
> Protected routes require: `Authorization: Bearer {token}`  
> All requests/responses use `Content-Type: application/json`  
> Locale: `Accept-Language: ar` or `Accept-Language: en`

---

## Registration Flow

> Registration is a multi-step process. The provider is identified by `phone_code` + `phone` across all steps — **no token required until after login**.
>
> Steps can be re-submitted to update data as long as OTP has not been verified yet.

```
Step 1 → Step 2 → Step 3 → Step 4 → Send OTP → Verify OTP → [wait for admin] → Login
```

---

### Step 1 — Personal Info

**`POST /register/step-1`** — Public

#### Request
```json
{
  "full_name":        "أحمد محمد",
  "national_id_type": "national_id",
  "national_id":      "1234567890",
  "gender":           "male",
  "nationality":      "saudi",
  "phone_code":       "966",
  "phone":            "512345678",
  "email":            "ahmed@example.com",
  "password":         "Secret@123",
  "password_confirmation": "Secret@123"
}
```

#### Field Reference
| Field | Rules |
|---|---|
| `national_id_type` | `national_id` / `iqama` / `passport` |
| `gender` | `male` / `female` |
| `nationality` | `saudi` / `resident` |
| `phone_code` | Valid country code e.g. `966` |
| `phone` | 7–15 digits, no leading zero, must start with `5` for Saudi numbers |
| `password` | min 8 chars, must match `password_confirmation` |

#### Response
```json
{
  "status": "success",
  "message": "Step 1 completed successfully.",
  "data": { "registration_status": "incomplete" }
}
```

> If this phone has already completed registration and is waiting for admin:
```json
{
  "status": "success",
  "message": "Your registration is complete and pending admin approval.",
  "data": { "registration_status": "pending" }
}
```

---

### Step 2 — Professional Info

**`POST /register/step-2`** — Public

#### Request
```json
{
  "phone_code":                  "966",
  "phone":                       "512345678",
  "provider_type_id":            1,
  "category_id":                 3,
  "subcategory_id":              7,
  "professional_license_number": "LIC-2024-001",
  "license_expiration_date":     "2026-12-31",
  "licensing_authority":         "هيئة المحامين السعوديين",
  "degree":                      "bachelor",
  "graduation_year":             2015,
  "university":                  "جامعة الملك سعود",
  "years_of_experience":         8
}
```

#### Field Reference
| Field | Rules |
|---|---|
| `provider_type_id` | Must exist in `provider_types` — fetch from `GET /provider-types` |
| `category_id` | Main category — fetch from `GET /categories` |
| `subcategory_id` | Sub category — fetch from `GET /subcategories?parent_id={id}` |
| `license_expiration_date` | `YYYY-MM-DD`, must be today or future |
| `degree` | `bachelor` / `master` / `phd` / `custom_diploma` |
| `graduation_year` | 4-digit year, 1900 – next year |
| `years_of_experience` | 0 – 100 |

---

### Step 3 — Location, Languages & Services

**`POST /register/step-3`** — Public

#### Request
```json
{
  "phone_code":   "966",
  "phone":        "512345678",
  "city_id":      1,
  "district_id":  4,
  "lat":          24.7136,
  "lng":          46.6753,
  "address":      "حي النخيل، الرياض",
  "brief":        "محامي متخصص في القضايا التجارية بخبرة 8 سنوات",
  "languages":    [1, 2],
  "services":     [3, 5, 8],
  "linkedin_link": "https://linkedin.com/in/ahmed",
  "website_link":  null
}
```

#### Field Reference
| Field | Rules |
|---|---|
| `city_id` | Must exist — fetch from `GET /cities` |
| `district_id` | Must exist — fetch from `GET /districts?city_id={id}` |
| `lat` | -90 to 90 |
| `lng` | -180 to 180 |
| `languages` | Array of language IDs (min 1) — fetch from `GET /languages` |
| `services` | Array of service IDs (min 1) — fetch from `GET /services` |
| `brief` | max 1000 chars |
| `linkedin_link` / `website_link` | nullable, valid URL |

---

### Step 4 — Documents

> Documents must be **pre-uploaded** via `POST /attachment` which returns a media `id`. Pass that `id` here — do not send raw files.

**`POST /register/step-4`** — Public

#### Request
```json
{
  "phone_code":              "966",
  "phone":                   "512345678",
  "national_id_doc":         101,
  "professional_license_doc": 102,
  "university_degree_doc":   103,
  "cv":                      104,
  "personal_image":          105,
  "courses_certificates":    [106, 107]
}
```

#### Field Reference
| Field | Required | Description |
|---|---|---|
| `national_id_doc` | ✅ | Media ID — national ID / iqama / passport scan |
| `professional_license_doc` | ✅ | Media ID — professional license |
| `university_degree_doc` | ✅ | Media ID — university degree |
| `cv` | ✅ | Media ID — CV / resume |
| `personal_image` | ✅ | Media ID — personal photo |
| `courses_certificates` | ❌ | Array of media IDs — optional certificates |

#### Response
Full registration summary — flat, no nested `provider` key:
```json
{
  "status": "success",
  "message": "Step 4 attachments uploaded successfully.",
  "data": {
    "id": 42,
    "full_name": "أحمد محمد",
    "email": "ahmed@example.com",
    "phone_code": "966",
    "phone": "512345678",
    "user_type": "provider",
    "account_status": "unverified",
    "national_id_type": "national_id",
    "national_id": "1234567890",
    "gender": "male",
    "nationality": "saudi",
    "professional_license_number": "LIC-2024-001",
    "license_expiration_date": "2026-12-31",
    "licensing_authority": "هيئة المحامين السعوديين",
    "degree": "bachelor",
    "graduation_year": 2015,
    "university": "جامعة الملك سعود",
    "years_of_experience": 8,
    "address": "حي النخيل، الرياض",
    "lat": "24.71360000",
    "lng": "46.67530000",
    "brief": "محامي متخصص...",
    "linkedin_link": "https://linkedin.com/in/ahmed",
    "website_link": null,
    "provider_type": { "id": 1, "name": "محامي" },
    "category":      { "id": 3, "name": "قانوني" },
    "subcategory":   { "id": 7, "name": "تجاري" },
    "city":          { "id": 1, "name": "الرياض" },
    "district":      { "id": 4, "name": "النخيل" },
    "services":      [{ "id": 3, "name": "استشارة قانونية" }],
    "languages":     [{ "id": 1, "name": "العربية" }, { "id": 2, "name": "الإنجليزية" }],
    "personal_image":           { "id": 105, "url": "https://...", "type": "image", "option": "personal_image", "is_single": true },
    "national_id_doc":          { "id": 101, "url": "https://...", "type": "file", "option": "national_id_doc", "is_single": true },
    "professional_license_doc": { "id": 102, "url": "https://...", "type": "file", "option": "professional_license_doc", "is_single": true },
    "university_degree_doc":    { "id": 103, "url": "https://...", "type": "file", "option": "university_degree_doc", "is_single": true },
    "cv":                       { "id": 104, "url": "https://...", "type": "file", "option": "cv", "is_single": true },
    "certificates":             [{ "id": 106, "url": "https://...", "type": "file", "option": "courses_certificates", "is_single": false }],
    "courses_certificates":     [{ "id": 106, "url": "https://...", "type": "file", "option": "courses_certificates", "is_single": false }]
  }
}
```

---

### Send OTP

**`POST /register/send-otp`** — Public

```json
{ "phone_code": "966", "phone": "512345678" }
```

> Triggers a 6-digit OTP (currently fixed to `111111` in development).  
> OTP expires in **10 minutes**.

---

### Verify OTP

**`POST /register/verify-otp`** — Public

```json
{
  "phone_code": "966",
  "phone":      "512345678",
  "otp":        "111111"
}
```

> On success: `account_status` → `pending`, provider waits for admin approval.  
> Admins will approve or reject via the dashboard.  
> Provider receives a push notification with the result.

---

### Registration Status Reference

| `registration_status` | Meaning | Frontend action |
|---|---|---|
| `incomplete` | Steps not all done | Continue to next step |
| `pending` | OTP verified, waiting admin | Show waiting screen |

> After admin accepts: provider can log in normally.  
> After admin rejects: login returns a rejection message with no `registration_status`.

---

## Authentication

### Login

**`POST /auth/login`** — Public

```json
{
  "email":        "ahmed@example.com",
  "password":     "Secret@123",
  "device_token": "fcm_token_here",
  "device_type":  "web"
}
```

#### Possible responses

| Condition | HTTP | Response |
|---|---|---|
| Valid credentials, accepted | 200 | Token + full profile |
| Wrong credentials | 422 | `"Invalid credentials"` |
| `account_status = pending` | 403 | `{ "registration_status": "pending" }` |
| `account_status = rejected` | 403 | Rejection message, no data |
| `account_status = unverified` | 403 | Not approved message |
| Account disabled by admin | 403 | Contact support message |

#### Success response shape
```json
{
  "status": "success",
  "message": "Logged in successfully",
  "data": {
    "id": 42,
    "uuid": "...",
    "full_name": "أحمد محمد",
    "email": "ahmed@example.com",
    "phone": "512345678",
    "phone_code": "966",
    "user_type": "provider",
    "locale": "ar",
    "allow_notifications": true,
    "is_active": true,
    "is_admin_active_user": true,
    "avatar": "https://...",
    "token": "eyJ...",
    "national_id_type": "national_id",
    "...": "... (full provider profile — same as GET /profile)"
  }
}
```

---

### Logout

**`POST /auth/logout`** — 🔒 Protected

No body required. Pass the `agent_token` header if available to deactivate the device.

---

### Forgot Password

> 3-step flow. No authentication required.

**Step 1** — `POST /auth/forgot-password`
```json
{ "email": "ahmed@example.com" }
```

**Resend OTP** — `POST /auth/resend-code`
```json
{ "email": "ahmed@example.com" }
```

**Step 2** — `POST /auth/verify-otp`
```json
{ "email": "ahmed@example.com", "otp": "111111" }
```
Returns: `{ "reset_token": "..." }`

**Step 3** — `POST /auth/reset-password`
```json
{
  "email":                 "ahmed@example.com",
  "reset_token":           "...",
  "password":              "NewSecret@123",
  "password_confirmation": "NewSecret@123"
}
```

---

## Profile

> All profile endpoints require `Authorization: Bearer {token}`.

### Get Profile

**`GET /profile`**

Returns the full provider profile — same shape as the login success response.

---

### Update Profile

**`PUT /profile`** — Send only the fields you want to change.

```json
{
  "full_name":              "أحمد علي",
  "locale":                 "en",
  "allow_notifications":    true,
  "is_available":           true,
  "brief":                  "محامي متخصص في القضايا التجارية",
  "address":                "حي العليا، الرياض",
  "lat":                    24.7136,
  "lng":                    46.6753,
  "city_id":                1,
  "district_id":            4,
  "linkedin_link":          "https://linkedin.com/in/ahmed",
  "website_link":           "https://ahmed-law.com",
  "years_of_experience":    9,
  "license_expiration_date": "2027-06-30",
  "languages":              [1, 2, 3],
  "personal_image":         108,
  "cv":                     109,
  "professional_license_doc": 110,
  "courses_certificates":   [111, 112]
}
```

#### Field Reference
| Field | Type | Description |
|---|---|---|
| `is_available` | boolean | Provider availability status — controls if provider appears in search results and can receive new orders |
| `license_expiration_date` | date | Can be updated without re-approval (YYYY-MM-DD, must be today or future) |
| `languages` | array | Replaces existing languages entirely (sync) |
| `personal_image`, `cv`, `professional_license_doc` | integer | Pre-uploaded media IDs |
| `courses_certificates` | array | Array of media IDs |

> **All fields are optional (`sometimes`). Only send what changed.**  
> **Note:** `email`, `phone`, and `password` CANNOT be changed via this endpoint for security reasons.  
> Use dedicated endpoints instead:
> - Email: `POST /profile/change-email` → `POST /profile/verify-change-email`
> - Phone: `POST /profile/change-phone` → `POST /profile/verify-change-phone`
> - Password: `PUT /profile/change-password`
>
> Media fields accept pre-uploaded media IDs (from `POST /attachment`).  
> `languages` replaces the existing language list entirely (sync).

---

### Change Password

**`PUT /profile/change-password`**

```json
{
  "current_password":      "OldSecret@123",
  "password":              "NewSecret@123",
  "password_confirmation": "NewSecret@123"
}
```

---

### Change Phone

> 2-step flow with OTP verification.

**Step 1** — `POST /profile/change-phone`
```json
{ "phone_code": "966", "phone": "598765432" }
```
Sends OTP to the new number. Phone is stored in `pending_phone` until verified.

**Step 2** — `POST /profile/verify-change-phone`
```json
{ "code": "111111" }
```
Verifies OTP and updates phone permanently.

---

### Change Email

> 2-step flow with OTP verification (email cannot be changed via PUT /profile for security).

**Step 1** — `POST /profile/change-email`
```json
{ "email": "newemail@example.com" }
```
Sends OTP to the new email. Email is stored in `pending_email` until verified.

**Step 2** — `POST /profile/verify-change-email`
```json
{ "code": "111111" }
```
Verifies OTP and updates email permanently.

---

### Resend OTP (Phone or Email Change)

**`POST /profile/resend-code`**

Intelligently resends OTP based on what's pending:
- If `pending_phone` exists → resends phone OTP
- If `pending_email` exists → resends email OTP
- If neither exists → returns error

No body required — automatically detects pending change type.

---

## Roles & Permissions

> Provider role and permission management for team collaboration.

### Roles Management

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/roles` | List provider roles |
| POST | `/roles` | Create new role |
| GET | `/roles/{id}` | Show role details |
| PUT | `/roles/{id}` | Update role |
| DELETE | `/roles/{id}` | Delete role |

#### List Provider Roles
**`GET /roles`**

**Query Parameters:**
- `paginate` (boolean, default: true) - Enable/disable pagination
- `per_page` (integer, default: 15) - Items per page

**Response:**
```json
{
  "status": "success",
  "message": "Data retrieved successfully", 
  "data": [
    {
      "id": 15,
      "name": "محرر المحتوى",
      "type": "provider",
      "provider_id": 42,
      "permissions_count": 5,
      "users_count": 2,
      "created_at": 1725198388
    }
  ]
}
```

#### Create Provider Role
**`POST /roles`**

**Request:**
```json
{
  "name": "محرر المحتوى",
  "permissions": [12, 15, 23, 28, 31]
}
```

**Response:**
```json
{
  "status": "success",
  "message": "Role created successfully",
  "data": {
    "id": 15,
    "name": "محرر المحتوى",
    "type": "provider", 
    "provider_id": 42,
    "permissions_count": 5,
    "users_count": 0,
    "permissions": [
      {
        "id": 12,
        "title": "عرض الطلبات"
      }
    ],
    "created_at": 1725198388
  }
}
```

### Permissions Management

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/permissions` | List available permissions |
| GET | `/permissions/grouped` | Permissions grouped by module |
| GET | `/permissions/my-permissions` | Current user permissions |

#### List Provider Permissions
**`GET /permissions`**

**Response:**
```json
{
  "status": "success", 
  "message": "Data retrieved successfully",
  "data": [
    {
      "id": 12,
      "title": "عرض الطلبات"
    },
    {
      "id": 13,
      "title": "تفاصيل الطلب"
    }
  ]
}
```

#### Permissions Grouped
**`GET /permissions/grouped`**

**Response:**
```json
{
  "status": "success",
  "message": "Data retrieved successfully",
  "data": {
    "Service Orders": [
      {
        "id": 12,
        "title": "عرض الطلبات"
      }
    ],
    "Profile Management": [
      {
        "id": 20,
        "title": "تحديث الملف الشخصي"
      }
    ]
  }
}
```

### Provider Admin Management

> Main providers can create and manage provider_admin accounts for their team.

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/admins` | List provider admins |
| POST | `/admins` | Create provider admin |
| GET | `/admins/{id}` | Show admin details |
| PUT | `/admins/{id}` | Update admin |
| DELETE | `/admins/{id}` | Delete admin |

#### Create Provider Admin
**`POST /admins`** — 🔒 Main Provider Only

**Request:**
```json
{
  "full_name": "أحمد المساعد",
  "email": "ahmed.assistant@example.com",
  "phone": "512345679",
  "password": "Secret@123",
  "password_confirmation": "Secret@123",
  "roles": [15, 18]
}
```

**Response:**
```json
{
  "status": "success",
  "message": "Provider admin created successfully",
  "data": {
    "id": 55,
    "full_name": "أحمد المساعد",
    "email": "ahmed.assistant@example.com",
    "user_type": "provider_admin",
    "parent_provider_id": 42,
    "roles": [...],
    "created_at": 1725198388
  }
}
```

---

## Service Prices

> Providers set their own price per service. Prices must be within the admin-defined range (`price_from` / `price_to`) for each service.

**`PUT /profile/service-prices`**

```json
{
  "services": [
    { "service_id": 3, "price": 250.00 },
    { "service_id": 5, "price": 400.00 }
  ]
}
```

> - `service_id` must be one of the provider's registered services (from registration step 3).  
> - If the service has `price_from` / `price_to`, price will be validated against that range.  
> - This endpoint uses `syncWithoutDetaching` — only the submitted services are updated, others stay untouched.

#### Response
```json
{
  "status": "success",
  "message": "Service prices updated successfully",
  "data": [
    {
      "service_id":  3,
      "title":       "استشارة قانونية",
      "price":       250.00,
      "price_from":  100.00,
      "price_to":    500.00
    }
  ]
}
```

---

## Schedules

> Weekly availability schedule. 7 days, each day can be active or inactive.  
> If `is_active` is `false`, `start_time` and `end_time` are ignored and stored as `null`.

### Get Schedules

**`GET /profile/schedules`** — 🔒 Protected

Always returns all 7 days even if some are not set yet (unset days default to `is_active: false`).

```json
{
  "status": "success",
  "message": "Data retrieved successfully",
  "data": [
    { "day_of_week": "sunday",    "is_active": false, "start_time": null,    "end_time": null    },
    { "day_of_week": "monday",    "is_active": true,  "start_time": "09:00", "end_time": "17:00" },
    { "day_of_week": "tuesday",   "is_active": true,  "start_time": "09:00", "end_time": "17:00" },
    { "day_of_week": "wednesday", "is_active": true,  "start_time": "09:00", "end_time": "17:00" },
    { "day_of_week": "thursday",  "is_active": true,  "start_time": "09:00", "end_time": "15:00" },
    { "day_of_week": "friday",    "is_active": false, "start_time": null,    "end_time": null    },
    { "day_of_week": "saturday",  "is_active": false, "start_time": null,    "end_time": null    }
  ]
}
```

---

### Set Schedules

**`PUT /profile/schedules`** (also accepts `POST`) — 🔒 Protected

Send all 7 days. Each day replaces the previous entry (upsert by `user_id` + `day_of_week`).

```json
{
  "schedules": [
    { "day_of_week": "sunday",    "is_active": false, "start_time": null,    "end_time": null    },
    { "day_of_week": "monday",    "is_active": true,  "start_time": "09:00", "end_time": "17:00" },
    { "day_of_week": "tuesday",   "is_active": true,  "start_time": "09:00", "end_time": "17:00" },
    { "day_of_week": "wednesday", "is_active": true,  "start_time": "09:00", "end_time": "17:00" },
    { "day_of_week": "thursday",  "is_active": true,  "start_time": "09:00", "end_time": "15:00" },
    { "day_of_week": "friday",    "is_active": false, "start_time": null,    "end_time": null    },
    { "day_of_week": "saturday",  "is_active": false, "start_time": null,    "end_time": null    }
  ]
}
```

#### Field Reference
| Field | Rules |
|---|---|
| `schedules` | Array, min 1, max 7 entries |
| `day_of_week` | `sunday` / `monday` / `tuesday` / `wednesday` / `thursday` / `friday` / `saturday` |
| `is_active` | `true` / `false` |
| `start_time` | `HH:MM` (24h), required when `is_active: true` |
| `end_time` | `HH:MM` (24h), required when `is_active: true`, must be after `start_time` |

Returns the same shape as `GET /profile/schedules`.

---

## Wallet

**`GET /wallet`** — Balance  
**`GET /wallet/transactions`** — Transaction history  
**`GET /wallet/withdrawal-requests`** — Withdrawal history  
**`GET /wallet/bank-account`** — Get saved bank account  
**`PUT /wallet/bank-account`** — Save bank account  
**`POST /wallet/withdraw`** — Request withdrawal  

---

## Lookup Endpoints (Public)

> Used during registration steps to populate dropdowns.

| Endpoint | Description | Params |
|---|---|---|
| `GET /provider-types` | Provider types | `?search=` |
| `GET /categories` | Main categories | `?search=`, `?with_content=true` |
| `GET /subcategories` | Subcategories | `?parent_id=`, `?search=`, `?with_content=true` |
| `GET /services` | Services | `?subcategory_id=`, `?search=` |
| `GET /languages` | Languages | `?search=` |
| `GET /cities` | Cities | `?region_id=`, `?has_districts=true` |
| `GET /districts` | Districts | `?city_id=` |

All lookup responses return: `[{ "id": 1, "name": "..." }]`

---

## Common Patterns

### Standard Response
```json
{
  "status": "success",
  "message": "...",
  "data": { ... }
}
```

### Error Response
```json
{
  "status": "fail",
  "message": "The phone field is required.",
  "data": {
    "phone": ["The phone field is required."]
  }
}
```

### Pre-uploading Files

> All media (documents, images, PDFs) must be uploaded **before** submitting step 4 or updating profile. The upload returns a media `id` — pass that `id` in your request.

**`POST /attachment`** — Public  
**`Content-Type: multipart/form-data`**

#### Single file upload

| Field | Required | Description |
|---|---|---|
| `file` | ✅ | The binary file |
| `media_type` | ✅ | `image` / `file` / `pdf` / `audio` / `video` |
| `model` | ✅ | Model name — use `User` for all provider documents |
| `option` | ✅ | Media collection name — see table below |
| `is_single` | ✅ | `true` if this replaces an existing single file, `false` for multi-file collections |
| `model_id` | ❌ | Leave empty during registration (provider not yet assigned) |
| `deleted_media` | ❌ | Media ID to delete when replacing a file |

#### Bulk file upload (multiple files at once)

Replace `file` with `files[]`:
```
files[0]=<binary>
files[1]=<binary>
media_type=file
model=User
option=documents
is_single=false
```

#### `option` values for provider documents

| Field in step 4 / profile | `media_type` | `option` | `is_single` |
|---|---|---|---|
| `national_id_doc` | `file` | `documents` | `true` |
| `professional_license_doc` | `file` | `documents` | `true` |
| `university_degree_doc` | `file` | `documents` | `true` |
| `cv` | `file` | `documents` | `true` |
| `personal_image` | `image` | `documents` | `true` |
| `courses_certificates` | `file` | `documents` | `false` |

#### Example — upload national ID doc
```
POST /attachment
Content-Type: multipart/form-data

file=<binary>
media_type=file
model=User
option=documents
is_single=true
```

#### Response
```json
{
  "status": "success",
  "message": "File uploaded successfully",
  "data": {
    "id": 101,
    "path": "https://example.com/storage/files/filename.pdf",
    "type": "file",
    "option": "documents",
    "model": "User",
    "model_id": null,
    "is_single": true
  }
}
```

Then pass `101` as the value for `national_id_doc` (or whichever field) in step 4.

#### Delete a media file
```
POST /attachment/delete/{id}
```


---

## Service Orders

> Service orders are created by clients who specifically choose you as their provider. These orders include dynamic form data, scheduled dates, and a complete workflow with Golden Guarantee protection.
>
> 📘 **Detailed Flow Documentation:** [Provider Service Order Flow](./PROVIDER_SERVICE_ORDER_FLOW.md)
>
> 💬 **Chat Integration:** Every order includes a `chat_id` for real-time communication with the client throughout the order lifecycle.

### Order Lifecycle
```
pending → accepted → active → provider_finished → completed
```

**Key Actions:**
- `accept` / `reject` a pending order
- `start` working (client can no longer cancel)
- `upload-files` progressively during work
- `finish` when all work is done (validates files uploaded)
- Client confirms OR files Golden Guarantee OR auto-complete after 24h

---

### List All Orders

**`GET /service-orders`** — 🔒 Protected

Query Parameters:
- `status` (optional): Filter by status
  - `pending`, `accepted`, `active`, `provider_finished`,
  - `pending_admin_review`, `completed`, `cancelled`, `rejected`
- `page` (optional): Page number

**Response:**
```json
{
    "status": "success",
    "message": "Data retrieved successfully",
    "data": [
        {
            "id": 1,
            "order_number": "ORD-1",
            "status": "pending",
            
            "scheduled_date": "2026-09-15",
            "scheduled_time": "14:00",
            
            "form_data": [
                {
                    "field_key": "case_type",
                    "label_ar": "نوع القضية",
                    "label_en": "Case Type",
                    "answer": "civil"
                },
                {
                    "field_key": "case_documents",
                    "label_ar": "مستندات القضية",
                    "label_en": "Case Documents",
                    "answer": [
                        {
                            "id": 101,
                            "url": "https://example.com/storage/uploads/doc1.pdf",
                            "type": "pdf",
                            "name": "doc1.pdf"
                        }
                    ]
                }
            ],
            
            "service_price": 400.00,
            "work_files": [],
            
            "client_data": {
                "id": 10,
                "full_name": "أحمد محمد",
                "avatar": "https://..."
            },
            
            "service_data": {
                "id": 5,
                "title": "استشارة قانونية"
            },
            
            "paid_at": 1725379200,
            "accepted_at": null,
            "completed_at": null,
            "created_at": 1725379200
        }
    ],
    "meta": {
        "current_page": 1,
        "total": 10,
        "per_page": 15
    }
}
```

**Form Data Structure:**
- Text fields: `"answer": "text value"`
- Single media: `"answer": { "id": 101, "url": "...", "type": "pdf", "name": "..." }`
- Multiple media: `"answer": [{ "id": 101, ... }, { "id": 102, ... }]`

---

### Show Order Details

**`GET /service-orders/{id}`** — 🔒 Protected

Returns full order details including all form data, client documents, and your uploaded work files.

**Response:** Same structure as list, but single order object

---

### Accept Order

**`POST /service-orders/{id}/accept`** — 🔒 Protected

Accept a pending order.

**Response:**
```json
{
    "status": "success",
    "message": "Order accepted successfully",
    "data": {
        "id": 1,
        "status": "accepted",
        "accepted_at": 1725379300,
        // ... full order
    }
}
```

**What Happens:**
- Status: `pending` → `accepted`
- Client is notified
- Order appears in your accepted orders

---

### Reject Order

**`POST /service-orders/{id}/reject`** — 🔒 Protected

Decline a pending order.

**Response:**
```json
{
    "status": "success",
    "message": "Order rejected successfully",
    "data": {
        "id": 1,
        "status": "rejected",
        "rejected_at": 1725379300,
        // ... full order
    }
}
```

**What Happens:**
- Status: `pending` → `rejected`
- **Client is refunded to wallet** (full amount)
- Order cannot be reopened

---

### Start Work

**`POST /service-orders/{id}/start`** — 🔒 Protected

Begin working on an accepted order.

**Response:**
```json
{
    "status": "success",
    "message": "Order started successfully",
    "data": {
        "id": 1,
        "status": "active",
        "started_at": 1725379500,
        // ... full order
    }
}
```

**What Happens:**
- Status: `accepted` → `active`
- Client **can NO LONGER cancel** the order
- You can now upload work files
- Client is notified

---

### Upload Work Files (المخرجات)

**`POST /service-orders/{id}/upload-files`** — 🔒 Protected

Upload deliverables during work. Can be called multiple times.

**Request:**
```json
{
    "files": [201, 202, 203]
}
```

> Files must be pre-uploaded to `/attachment` with:
> - `media_type`: `pdf` / `image` / `file` / `audio` / `video`
> - `model`: `ServiceOrder`
> - `option`: `provider_work_files`
> - `is_single`: `false`

**Response:**
```json
{
    "status": "success",
    "message": "Work files uploaded successfully",
    "data": {
        "id": 1,
        "status": "active",
        
        "work_files": [
            {
                "id": 201,
                "url": "https://example.com/storage/uploads/report.pdf",
                "type": "pdf",
                "name": "report.pdf",
                "uploaded_at": 1725380000
            },
            {
                "id": 202,
                "url": "https://example.com/storage/uploads/analysis.docx",
                "type": "file",
                "name": "analysis.docx",
                "uploaded_at": 1725380000
            }
        ]
    }
}
```

**Notes:**
- Status stays `active` (not finished yet)
- Can call multiple times to add more files
- Client sees files in real-time
- Files are cumulative (new uploads don't replace old ones)

---

### Mark as Finished

**`POST /service-orders/{id}/finish`** — 🔒 Protected

Mark order as finished when all work is done.

**Response:**
```json
{
    "status": "success",
    "message": "Work completed successfully. Waiting for client confirmation.",
    "data": {
        "id": 1,
        "status": "provider_finished",
        "provider_finished_at": 1725380500,
        "work_files": [ /* all uploaded files */ ]
    }
}
```

**Validation Error (No Files):**
```json
{
    "status": "fail",
    "message": "You must upload at least one work file before marking as finished",
    "data": null
}
```

**What Happens:**
- Status: `active` → `provider_finished`
- Validates at least one file uploaded
- Auto-complete job scheduled (24 hours)
- Client is notified to review work

**Client Must Now:**
1. Confirm completion → You get paid ✅
2. File Golden Guarantee → Goes to admin review
3. Do nothing → Auto-complete after 24h → You get paid ✅

---

### Golden Guarantee Flow

When client files a complaint after `provider_finished`:

**Status:** `provider_finished` → `pending_admin_review`

**Admin Reviews:**
- **Approves Redo:** Status → `active`, `redo_count++` (you must redo work)
- **Rejects Complaint:** Status → `completed` (you get paid)

**If Admin Approves Redo:**
```
active (redo_count = 1)
  ↓ upload-files (upload corrected work)
active
  ↓ finish
provider_finished
  ↓ client confirms or auto-complete
completed ✅
```

---

### Order Status Reference

| Status | Description | Your Actions |
|---|---|---|
| `pending` | New order awaiting your response | Accept or Reject |
| `accepted` | You accepted, haven't started yet | Start work |
| `active` | Work in progress | Upload files, then Finish |
| `provider_finished` | Waiting for client confirmation | Wait (auto-complete after 24h) |
| `pending_admin_review` | Client filed Golden Guarantee | Wait for admin decision |
| `completed` | Order completed, you're paid ✅ | — |
| `rejected` | You rejected the order | — |
| `cancelled` | Client cancelled | — |

---

## Urgent Orders

> Urgent orders (طلبات عاجلة) are dispatched to ALL providers who can perform urgent orders. First provider to accept gets the order. No Golden Guarantee for urgent orders.
>
> 📘 **Detailed Flow Documentation:** [Provider Urgent Order Flow](./PROVIDER_URGENT_ORDER_FLOW.md)

### Order Lifecycle
```
searching_for_provider
  ├─ accept → in_progress (assigned to you)
  └─ reject → searching_for_provider (goes to others)

in_progress
  └─ Admin completes → completed (you get paid)
```

**Key Differences from Service Orders:**
- ❌ No Golden Guarantee (client cannot file complaints)
- ✅ Auto-complete immediately when work is done
- ✅ First-come-first-served (no pending acceptance period)
- ✅ Dispatched to ALL eligible providers

---

### Eligibility

Only providers with `can_perform_urgent_order = true` receive urgent orders.

Check your profile:
```json
GET /profile

{
    "data": {
        "can_perform_urgent_order": true
    }
}
```

> Contact admin to enable urgent order capability for your account.

---

### List Available Urgent Orders

**`GET /urgent-orders`** — 🔒 Protected

Shows all urgent orders dispatched to you with status `searching_for_provider`.

**Response:**
```json
{
    "status": "success",
    "message": "Orders retrieved successfully",
    "data": [
        {
            "id": 1,
            "uuid": "550e8400-e29b-41d4-a716-446655440000",
            "status": "searching_for_provider",
            "total_price": 500.00,
            
            "lat": 24.7136,
            "lng": 46.6753,
            "location": "الرياض، المملكة العربية السعودية",
            "phone_code": "+966",
            "phone": "501234567",
            
            "branch_destination": "فرع الرياض",
            "agency_type": "prior",
            "note": "حالة عاجلة تتطلب تمثيل فوري",
            
            "client_data": {
                "id": 10,
                "full_name": "أحمد محمد",
                "phone_code": "+966",
                "phone": "501234567",
                "avatar": "https://..."
            },
            
            "service_data": {
                "id": 5,
                "name": "تمثيل المحكمة"
            },
            "emergency_authority_data": {
                "id": 2,
                "name": "النيابة العامة"
            },
            "emergency_case_type_data": {
                "id": 3,
                "name": "قضية جنائية"
            },
            
            "completed_at": null,
            "created_at": 1725379200,
            "updated_at": 1725379200
        }
    ],
    "meta": {
        "current_page": 1,
        "total": 5,
        "per_page": 15
    }
}
```

**Notes:**
- Only shows orders where your status is `pending`
- Order disappears once you reject or another provider accepts
- Agency types: `prior` (وكالة مسبقة) or `new` (وكالة جديدة with Najiz)

---

### Show Urgent Order Details

**`GET /urgent-orders/{id}`** — 🔒 Protected

**Response:** Same structure as list, but single order object

**Error (Not Authorized):**
```json
{
    "status": "error",
    "message": "You are not authorized to view this order",
    "data": null
}
```

---

### Accept Urgent Order

**`POST /urgent-orders/{id}/accept`** — 🔒 Protected

Accept the order (first provider to accept gets it).

**Response (Success):**
```json
{
    "status": "success",
    "message": "Order accepted successfully",
    "data": {
        "id": 1,
        "status": "in_progress",
        "total_price": 500.00,
        // ... full order
    }
}
```

**Response (Already Taken):**
```json
{
    "status": "error",
    "message": "This order is no longer available",
    "data": null
}
```

**What Happens:**
- Status: `searching_for_provider` → `in_progress`
- Order assigned to you
- Other providers can no longer see it
- Client is notified

**Race Condition:**
- If another provider accepts first, you get "no longer available"
- This is normal - first come, first served

---

### Reject Urgent Order

**`POST /urgent-orders/{id}/reject`** — 🔒 Protected

Decline the order (stays available for others).

**Response:**
```json
{
    "status": "success",
    "message": "Order rejected successfully",
    "data": null
}
```

**What Happens:**
- Your status changes to `rejected`
- Order disappears from your list
- Order remains `searching_for_provider` for others
- System continues searching

---

### Auto-Retry System

If no provider accepts:
- **Retry Interval:** 5 minutes (configurable)
- **Max Retries:** 3 (configurable)
- **Absolute Timeout:** 30 minutes (configurable)

**Timeline:**
1. Initial dispatch (10:00 AM)
2. First retry (10:05 AM) - re-sent to ALL
3. Second retry (10:10 AM)
4. Third retry (10:15 AM)
5. Timeout (10:30 AM) - auto-cancel, client refunded

**Provider Impact:**
- Rejected orders may reappear during retries
- Can reject multiple times
- Once accepted by anyone, others can't see it

---

### Completion & Payment

**Completion:**
1. You accept order
2. You perform service at client location
3. **Admin marks as completed**
4. You get paid immediately

**No Client Confirmation:**
- Admin handles completion
- No file upload required
- No Golden Guarantee complaints

**Payment:**
```
Total Order Price: 500 SAR
Platform Fee (10%): -50 SAR
You Receive: 450 SAR
```

---

### Agency Types

**Prior Agency (وكالة مسبقة):**
```json
{
    "agency_type": "prior"
}
```
- Client has existing agency
- Just perform service

**New Agency (وكالة جديدة):**
```json
{
    "agency_type": "new"
}
```
- Client needs new agency via Najiz
- May need to guide client
- Static content: `GET /pages/urgent_order_new_agency`

---

### Error Responses

**Not Authorized:**
```json
{
    "status": "error",
    "message": "You are not authorized to perform urgent orders",
    "data": null
}
```
**Solution:** Contact admin to enable `can_perform_urgent_order`

**Order Taken:**
```json
{
    "status": "error",
    "message": "This order is no longer available",
    "data": null
}
```
**Reason:** Another provider accepted first

---

## Static Pages

**`GET /pages/{type}`** — Public

Fetch static content pages.

**Available Pages:**
- `terms_and_conditions`
- `privacy_policy`
- `about_us`
- `how_it_works`
- `urgent_order_prior_agency` - وكالة مسبقة info
- `urgent_order_new_agency` - وكالة جديدة + Najiz steps

**Response:**
```json
{
    "status": "success",
    "message": "Page retrieved successfully",
    "data": {
        "id": 1,
        "type": "terms_and_conditions",
        "title": "الشروط والأحكام",
        "content": "<p>محتوى الصفحة...</p>",
        "is_active": true
    }
}
```

---

## Contact Us

**`POST /contact-us`** — 🔒 Protected

Submit a contact/support request.

**Request:**
```json
{
    "complaint_type": "technical_issue",
    "priority": "high",
    "subject": "مشكلة في الطلبات",
    "message": "لا أستطيع رؤية الطلبات الجديدة"
}
```

**Field Reference:**
| Field | Values |
|---|---|
| `complaint_type` | `technical_issue`, `account_issue`, `payment_issue`, `general_inquiry`, `suggestion`, `complaint` |
| `priority` | `low`, `medium`, `high`, `urgent` |
| `subject` | Required, max 255 chars |
| `message` | Required, max 2000 chars |

**Response:**
```json
{
    "status": "success",
    "message": "Your message has been sent successfully",
    "data": {
        "id": 42,
        "subject": "مشكلة في الطلبات",
        "status": "pending",
        "created_at": 1725379200
    }
}
```

---

## Notifications

**`GET /notifications`** — List all notifications  
**`GET /notifications/{id}`** — Show specific notification  
**`PUT /notifications/{id}`** — Mark as read (or all if no ID)  
**`DELETE /notifications/{id}`** — Delete notification (or all if no ID)  
**`DELETE /notifications/bulk-delete`** — Delete multiple  

### Notification Types

**Service Orders:**
- `service_order_created` - New order received
- `service_order_confirmed` - Client confirmed completion
- `golden_guarantee_filed` - Client filed complaint
- `golden_guarantee_approved` - Admin approved redo
- `golden_guarantee_rejected` - Admin rejected complaint

**Urgent Orders:**
- `urgent_order_dispatched` - New urgent order
- `urgent_order_taken` - Another provider accepted
- `urgent_order_retry` - Order re-dispatched

**Account:**
- `provider_approved` - Registration approved
- `provider_rejected` - Registration rejected
- `account_suspended` - Account suspended by admin

---

## Quick Reference

### File Upload Options

| Upload For | `model` | `option` | `is_single` |
|---|---|---|---|
| Registration/Profile Docs | `User` | `documents` | varies |
| Service Order Work Files | `ServiceOrder` | `provider_work_files` | `false` |

### Order Status Flow

**Service Orders:**
```
pending → accepted → active → provider_finished → completed
```

**Urgent Orders:**
```
searching_for_provider → in_progress → completed
```

### Payment Timing

| Order Type | Payment Trigger |
|---|---|
| Service Order | Client confirms OR auto-complete after 24h |
| Urgent Order | Admin marks as completed |

---

## Additional Resources

- 📘 [Provider Service Order Flow](./PROVIDER_SERVICE_ORDER_FLOW.md) - Complete service order guide
- 📘 [Provider Urgent Order Flow](./PROVIDER_URGENT_ORDER_FLOW.md) - Complete urgent order guide
- 📘 [Service Order Media Flow](../SERVICE_ORDER_MEDIA_FLOW.md) - Client media upload details
- 📘 [Provider Work Files Flow](../PROVIDER_WORK_FILES_FLOW.md) - Provider file upload details
- 📘 [Provider Chat Guide](./PROVIDER_CHAT_GUIDE.md) - **Chat endpoints + Socket/Real-Time integration guide**

---

## Chats

> Full details including response shapes, field reference, and Socket/Redis integration:
> 📘 **[Provider Chat Guide](./PROVIDER_CHAT_GUIDE.md)**

| Method | Endpoint | Description |
|---|---|---|
| GET | `/chats` | List all chats (sorted by latest activity, includes unread count) |
| GET | `/chats/{chat_id}` | Show paginated messages — auto-marks incoming as read |
| POST | `/chats/{chat_id}/messages` | Send a message (blocked if chat is closed) |

### Quick Reference

| Event | Socket Channel | Type key |
|---|---|---|
| New message received | `nokhba-chat` | `message` |
| Other party read your messages | `nokhba-chat` | `read_receipt` |
| Urgent order accepted (chat created) | `nokhba-urgent-orders` | `urgent_order_accepted` |

