# Avatar & Fleet Driver KYC — API changes

This document covers **recent API changes** for:

- **Avatar upload** via base64 in the request body (write-only `avatar`); backend stores an absolute URL in `avatar_url`.
- **Fleet owner driver CRUD** accepting the **same KYC document types and `expiry_date`** as individual drivers.

All endpoints use the standard response envelope:

```json
{
  "status_code": 200,
  "message": "Human-readable message.",
  "error": null,
  "data": {}
}
```

HTTP status matches `status_code`. Validation failures return `400` with field errors in `error`.

---

## Avatar convention (all endpoints below)

| Direction | Field | Format |
|-----------|-------|--------|
| Request (write) | `avatar` | Base64 image string. Optional `data:image/jpeg;base64,` (or png/gif/webp) prefix. JPEG, PNG, GIF, WebP only. |
| Response (read) | `avatar_url` | Absolute URL stored in DB (e.g. `https://api.example.com/media/avatars/user/2026/07/20/abc123.jpg`). Empty string when not set. |

`avatar` is **write-only** — never returned in responses. Use `avatar_url` to display the image.

---

## 1. Individual driver signup

### `POST /api/transporter/register/`

**Auth:** None

**New field:** optional `avatar` on `account_type=DRIVER` signup.

**Request:**

```json
{
  "email": "driver@example.com",
  "password": "SecurePass123",
  "first_name": "Ahmed",
  "last_name": "Raza",
  "phone": "03001234567",
  "account_type": "DRIVER",
  "company_name": "",
  "local": true,
  "country_to_country": false,
  "language": "en",
  "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
```

**Response `201`:**

```json
{
  "status_code": 201,
  "message": "Transporter registered successfully.",
  "error": null,
  "data": {
    "token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b",
    "user_id": 8,
    "email": "driver@example.com"
  }
}
```

Avatar is saved on the transporter profile. After login, use **`GET /api/transporter/profile/`** to read `avatar_url`.

---

## 2. Individual driver profile

### `GET /api/transporter/profile/`

**Auth:** Transporter

**Response `200` (excerpt — new field):**

```json
{
  "status_code": 200,
  "message": "Profile retrieved successfully.",
  "error": null,
  "data": {
    "user_id": 8,
    "email": "driver@example.com",
    "first_name": "Ahmed",
    "last_name": "Raza",
    "phone": "03001234567",
    "language": "en",
    "account_type": "DRIVER",
    "company_name": "",
    "local": true,
    "country_to_country": false,
    "documents_verified": false,
    "tc_id": "123",
    "tc_u_id": "A1B2C3D4E5",
    "avatar_url": "https://api.example.com/media/avatars/user/2026/07/20/abc123.jpg",
    "vehicle": null,
    "vehicles": [],
    "created_at": "2026-03-19T10:00:00Z",
    "updated_at": "2026-03-19T10:00:00Z"
  }
}
```

### `PATCH /api/transporter/profile/`

**Auth:** Transporter

**Request (partial):**

```json
{
  "first_name": "Ahmed",
  "last_name": "Raza",
  "phone": "03009876543",
  "language": "ur",
  "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
```

**Response `200`:** Same shape as GET; `data.avatar_url` contains the new absolute URL.

---

## 3. Vehicle CRUD

### `POST /api/transporter/vehicles/`

**Auth:** Transporter

**Request:**

```json
{
  "vehicle_type": "Truck",
  "registration_number": "ABC-123",
  "load_capacity": "15000.00",
  "max_length_m": "6.500",
  "max_width_m": "2.450",
  "max_height_m": "2.600",
  "special_features": "refrigeration",
  "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
```

**Response `201`:**

```json
{
  "status_code": 201,
  "message": "Vehicle created successfully.",
  "error": null,
  "data": {
    "id": 42,
    "owner_id": 8,
    "vehicle_type": "Truck",
    "registration_number": "ABC-123",
    "load_capacity": "15000.00",
    "max_length_m": "6.500",
    "max_width_m": "2.450",
    "max_height_m": "2.600",
    "special_features": "refrigeration",
    "avatar_url": "https://api.example.com/media/avatars/vehicle/2026/07/20/def456.jpg",
    "is_active": false,
    "is_verified": false,
    "assigned_driver_id": null,
    "assigned_driver_email": null,
    "verified_at": null,
    "created_at": "2026-07-20T11:00:00Z",
    "updated_at": "2026-07-20T11:00:00Z"
  }
}
```

### `GET /api/transporter/vehicles/`

**Auth:** Transporter

**Response `200`:** `data` is an array of vehicle objects; each includes `avatar_url`.

### `GET /api/transporter/vehicles/{id}/`

**Auth:** Transporter

**Response `200`:** Single vehicle object including `avatar_url`.

### `PATCH /api/transporter/vehicles/{id}/`

**Auth:** Transporter

**Request (partial):**

```json
{
  "special_features": "refrigeration, GPS",
  "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
```

**Response `200`:** Updated vehicle object with new `avatar_url`.

---

## 4. Fleet owner — driver CRUD

**Auth:** Fleet owner (`account_type=FLEET_OWNER`)

### Allowed KYC document types (same as individual driver)

| `document_type` | Upload | Notes |
|-----------------|--------|-------|
| `DRIVER_LICENSE` | `file` + `file_back` | Two-sided; both required on first upload |
| `COUNTRY_GCC` | `file` + `file_back` | Two-sided; also send `gcc_country` |
| `PASSPORT_COPY` | `file` only | Requires `passport_number` |
| `PERMIT` | `file` only | Single-sided |
| `NOC` | `file` only | Optional |

`VEHICLE_REGISTRATION` is **not** accepted on driver KYC.

Each document may include optional **`expiry_date`** (`YYYY-MM-DD`). Re-posting the same `document_type` **upserts** that row (files and/or expiry).

Files are base64 (optional `data:...;base64,` prefix), same as `/api/transporter/documents/`.

---

### `POST /api/transporter/drivers/`

**Request:**

```json
{
  "email": "fleet-driver@example.com",
  "password": "SecurePass123",
  "first_name": "Ali",
  "last_name": "Khan",
  "phone": "03001234567",
  "language": "en",
  "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
  "documents": [
    {
      "document_type": "DRIVER_LICENSE",
      "file": "data:image/png;base64,iVBORw0KGgo...",
      "file_back": "data:image/png;base64,iVBORw0KGgo...",
      "expiry_date": "2027-12-31"
    },
    {
      "document_type": "PASSPORT_COPY",
      "file": "data:image/png;base64,iVBORw0KGgo...",
      "expiry_date": "2030-01-15"
    }
  ]
}
```

**Response `201`:**

```json
{
  "status_code": 201,
  "message": "Driver added to fleet successfully.",
  "error": null,
  "data": {
    "id": 88,
    "email": "fleet-driver@example.com",
    "first_name": "Ali",
    "last_name": "Khan",
    "account_type": "TRANSPORTER_DRIVER",
    "phone": "03001234567",
    "language": "en",
    "documents_verified": false,
    "tc_id": "999",
    "avatar_url": "https://api.example.com/media/avatars/user/2026/07/20/ghi789.jpg",
    "documents": [
      {
        "id": 1,
        "document_type": "DRIVER_LICENSE",
        "file": "kyc/2026/07/20/....png",
        "file_url": "https://api.example.com/media/kyc/2026/07/20/....png",
        "file_back": "kyc/2026/07/20/....png",
        "file_back_url": "https://api.example.com/media/kyc/2026/07/20/....png",
        "verified": false,
        "expiry_date": "2027-12-31",
        "submitted_at": "2026-07-20T11:30:00Z",
        "reviewed_at": null
      },
      {
        "id": 2,
        "document_type": "PASSPORT_COPY",
        "file": "kyc/2026/07/20/....png",
        "file_url": "https://api.example.com/media/kyc/2026/07/20/....png",
        "file_back": "",
        "file_back_url": null,
        "verified": false,
        "expiry_date": "2030-01-15",
        "submitted_at": "2026-07-20T11:30:00Z",
        "reviewed_at": null
      }
    ],
    "is_active": true,
    "linked_at": "2026-07-20T11:30:00Z"
  }
}
```

---

### `GET /api/transporter/drivers/`

**Response `200`:**

```json
{
  "status_code": 200,
  "message": "Fleet drivers retrieved successfully.",
  "error": null,
  "data": {
    "count": 1,
    "drivers": [
      {
        "id": 88,
        "email": "fleet-driver@example.com",
        "first_name": "Ali",
        "last_name": "Khan",
        "account_type": "TRANSPORTER_DRIVER",
        "phone": "03001234567",
        "language": "en",
        "documents_verified": false,
        "tc_id": "999",
        "avatar_url": "https://api.example.com/media/avatars/user/2026/07/20/ghi789.jpg",
        "documents": [],
        "is_active": true,
        "linked_at": "2026-07-20T11:30:00Z"
      }
    ]
  }
}
```

---

### `GET /api/transporter/drivers/{id}/`

**Response `200`:** Same driver object as POST `data` (includes `avatar_url` and `documents`).

---

### `PATCH /api/transporter/drivers/{id}/`

**Request (partial — profile + document upsert):**

```json
{
  "first_name": "Ali",
  "phone": "03009998877",
  "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
  "documents": [
    {
      "document_type": "PERMIT",
      "expiry_date": "2026-09-01"
    }
  ]
}
```

Updating documents without files is allowed when the document already exists (expiry-only update).

**Response `200`:**

```json
{
  "status_code": 200,
  "message": "Driver updated successfully.",
  "error": null,
  "data": {
    "id": 88,
    "email": "fleet-driver@example.com",
    "first_name": "Ali",
    "last_name": "Khan",
    "account_type": "TRANSPORTER_DRIVER",
    "phone": "03009998877",
    "language": "en",
    "documents_verified": false,
    "tc_id": "999",
    "avatar_url": "https://api.example.com/media/avatars/user/2026/07/20/new-avatar.jpg",
    "documents": [
      {
        "id": 3,
        "document_type": "PERMIT",
        "file": "kyc/2026/07/20/....png",
        "file_url": "https://api.example.com/media/kyc/2026/07/20/....png",
        "file_back": "",
        "file_back_url": null,
        "verified": false,
        "expiry_date": "2026-09-01",
        "submitted_at": "2026-07-20T12:00:00Z",
        "reviewed_at": null
      }
    ],
    "is_active": true,
    "linked_at": "2026-07-20T11:30:00Z"
  }
}
```

---

### `GET /api/transporter/drivers/{id}/documents/`

**Response `200`:**

```json
{
  "status_code": 200,
  "message": "Driver documents retrieved successfully.",
  "error": null,
  "data": [
    {
      "id": 1,
      "document_type": "DRIVER_LICENSE",
      "file": "kyc/2026/07/20/....png",
      "file_url": "https://api.example.com/media/kyc/2026/07/20/....png",
      "file_back": "kyc/2026/07/20/....png",
      "file_back_url": "https://api.example.com/media/kyc/2026/07/20/....png",
      "verified": false,
      "expiry_date": "2027-12-31",
      "submitted_at": "2026-07-20T11:30:00Z",
      "reviewed_at": null
    }
  ]
}
```

---

### `POST /api/transporter/drivers/{id}/documents/`

Upload or upsert **one** document for a linked fleet driver.

**Request:**

```json
{
  "document_type": "COUNTRY_GCC",
  "file": "data:image/png;base64,iVBORw0KGgo...",
  "file_back": "data:image/png;base64,iVBORw0KGgo...",
  "expiry_date": "2028-03-01"
}
```

**Response `201`:**

```json
{
  "status_code": 201,
  "message": "Driver document uploaded successfully.",
  "error": null,
  "data": {
    "id": 4,
    "document_type": "COUNTRY_GCC",
    "file": "kyc/2026/07/20/....png",
    "file_url": "https://api.example.com/media/kyc/2026/07/20/....png",
    "file_back": "kyc/2026/07/20/....png",
    "file_back_url": "https://api.example.com/media/kyc/2026/07/20/....png",
    "verified": false,
    "expiry_date": "2028-03-01",
    "submitted_at": "2026-07-20T12:15:00Z",
    "reviewed_at": null
  }
}
```

---

## Error examples

**Invalid avatar (not an image) — `400`:**

```json
{
  "status_code": 400,
  "message": "Validation failed.",
  "error": {
    "avatar": ["Must be a valid image file (JPEG, PNG, GIF, or WebP)."]
  },
  "data": null
}
```

**Invalid fleet driver document type — `400`:**

```json
{
  "status_code": 400,
  "message": "Validation failed.",
  "error": {
    "documents": [
      {
        "0": {
          "document_type": [
            "Invalid document_type for this account. Allowed: COUNTRY_GCC, DRIVER_LICENSE, NOC, PASSPORT_COPY, PERMIT."
          ]
        }
      }
    ]
  },
  "data": null
}
```

**Two-sided document missing back on first upload — `400`:**

```json
{
  "status_code": 400,
  "message": "Validation failed.",
  "error": {
    "file_back": ["Back file is required."]
  },
  "data": null
}
```

---

## Endpoint summary

| Method | Path | Change |
|--------|------|--------|
| POST | `/api/transporter/register/` | Optional `avatar` (DRIVER) |
| GET | `/api/transporter/profile/` | Returns `avatar_url` |
| PATCH | `/api/transporter/profile/` | Optional `avatar` |
| POST | `/api/transporter/vehicles/` | Optional `avatar` → `avatar_url` |
| GET | `/api/transporter/vehicles/` | Returns `avatar_url` per vehicle |
| GET | `/api/transporter/vehicles/{id}/` | Returns `avatar_url` |
| PATCH | `/api/transporter/vehicles/{id}/` | Optional `avatar` |
| POST | `/api/transporter/drivers/` | Optional `avatar`, optional `documents[]` |
| GET | `/api/transporter/drivers/` | Returns `avatar_url`, `documents[]` per driver |
| GET | `/api/transporter/drivers/{id}/` | Returns `avatar_url`, `documents[]` |
| PATCH | `/api/transporter/drivers/{id}/` | Optional `avatar`, optional `documents[]` |
| GET | `/api/transporter/drivers/{id}/documents/` | **New** — list driver KYC docs |
| POST | `/api/transporter/drivers/{id}/documents/` | **New** — upload/upsert one doc |
