# Representation (Agent) API > **Prefix:** `/api/v1/representation` Representations are sales agents who earn commission on appointments booked through their referral. --- ## POST `/api/v1/representation` Create a new representation. **Permission:** `ROLE_ADMIN` ### Request Body (`application/json`) ```json { "full_name": "علی احمدی", "mobile_number": "09123456789", "city_id": 42, "commission_percent": 10, "bank_account": { "iban": "IR...", "account_number": "1234567890", "bank_name": "بانک ملت", "owner_name": "علی احمدی" } } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `full_name` | string | ✅ | Agent full name | | `mobile_number` | string | ✅ | Login mobile (creates a User account) | | `city_id` | integer | ❌ | City ID (FK to categories where bundle=city) | | `commission_percent` | float | ❌ | Commission rate (0–100) | | `bank_account` | object | ❌ | Bank details for settlements | ### Response `201` ```json { "success": true, "data": { "uuid": "rep-uuid-...", "full_name": "علی احمدی", "mobile_number": "09123456789", "city_id": 42, "commission_percent": 10, "active": true, "bank_account": { ... }, "created_at": 1717000000 } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_AUTH_006` | 403 | Not admin | | `ERR_CONFLICT_001` | 409 | Mobile number already in use | | `ERR_VALIDATION_001` | 422 | `mobile_number` فرمت معتبر موبایل ایران (`^09\d{9}$`) ندارد (`field: mobile_number`) | | `ERR_VALIDATION_002` | 422 | `mobile_number` یا `full_name` خالی | --- ## GET `/api/v1/representation/{uuid}` Get representation detail. **Permission:** `AUTH` — must be the representation's user or `ROLE_ADMIN` ### Path Parameters | Param | Type | Description | |-------|------|-------------| | `uuid` | string (UUID) | Representation UUID | ### Response `200` ```json { "success": true, "data": { "uuid": "...", "full_name": "علی احمدی", "mobile_number": "09123456789", "city_id": 42, "city_name": "تهران", "commission_percent": 10, "active": true, "bank_account": { ... }, "created_at": 1717000000 } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_FORBIDDEN_001` | 403 | Not owner or admin | | `ERR_NOT_FOUND_001` | 404 | Representation not found | --- ## PATCH `/api/v1/representation/{uuid}` Update representation. **Permission:** `AUTH` — must be the representation's user or `ROLE_ADMIN` ### Request Body (`application/json`) ```json { "full_name": "علی احمدی جدید", "city_id": 50, "commission_percent": 12, "bank_account": { ... }, "active": true } ``` All fields optional. ### Response `200` Updated representation object. ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_FORBIDDEN_001` | 403 | Not owner or admin | | `ERR_NOT_FOUND_001` | 404 | Representation not found | --- ## DELETE `/api/v1/representation/{uuid}` Delete a representation. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "message": "نماینده حذف شد" } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_AUTH_006` | 403 | Not admin | | `ERR_NOT_FOUND_001` | 404 | Representation not found | --- ## GET `/api/v1/representation/{uuid}/dashboard/monthly` Get monthly earnings dashboard for a representation. **Permission:** `AUTH` — must be the representation's user or `ROLE_ADMIN` ### Path Parameters | Param | Type | Description | |-------|------|-------------| | `uuid` | string (UUID) | Representation UUID | ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `year` | integer | ✅ | e.g. `2024` | | `month` | integer | ✅ | 1–12 | ### Response `200` ```json { "success": true, "data": { "period": { "year": 2024, "month": 6 }, "stats": { "total_appointments": 15, "total_revenue_rials": 7500000, "commission_rials": 750000, "daily": [ { "date": "2024-06-01", "appointments": 2, "revenue": 1000000, "commission": 100000 } ] } } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_FORBIDDEN_001` | 403 | Not owner or admin | | `ERR_NOT_FOUND_001` | 404 | Representation not found | --- ## GET `/api/v1/representation/{uuid}/dashboard/yearly` Get yearly earnings dashboard for a representation. **Permission:** `AUTH` — must be the representation's user or `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `year` | integer | ✅ | e.g. `2024` | ### Response `200` ```json { "success": true, "data": { "period": { "year": 2024 }, "months": [ { "month": 1, "appointments": 10, "revenue_rials": 5000000, "commission_rials": 500000 }, { "month": 2, "appointments": 8, "revenue_rials": 4000000, "commission_rials": 400000 } ], "totals": { "appointments": 97, "revenue_rials": 48500000, "commission_rials": 4850000 } } } ``` --- ## پنل نماینده (ROLE_REPRESENTATION) این endpointها برای کاربرِ دارای نقش `ROLE_REPRESENTATION` در پنل ادمین (`/admin`) هستند. مالکیت همیشه از کاربر جاری (`#[CurrentUser]` + `findByUser`) تعیین می‌شود؛ هیچ uuid/id ورودی برای تعیین مالکیت پذیرفته نمی‌شود. > **Permission (همه‌ی این بخش):** `ROLE_REPRESENTATION` ### GET `/api/v1/representation/me` پروفایل نماینده‌ی کاربر جاری. #### Response `200` ```json { "success": true, "data": { "data": { "uuid": "...", "full_name": "حامد حسینی", "mobile_number": "09120671756", "city_id": 132, "commission_percent": "10.00", "bank_account": null, "active": true, "created_at": 1718000000 } } } ``` > double-nested: مقدار با `data.data` استخراج می‌شود. #### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | کاربر جاری نماینده نیست | --- ### POST `/api/v1/representation/doctor` افزودن پزشک توسط نماینده. `representation_id` پزشک به‌صورت خودکار روی نماینده‌ی کاربر جاری ست می‌شود. #### Request Body ```json { "mobile": "0935...", "name": "دکتر ...", "gender": "man", "degree": "...", "medical_system_code": "...", "specialties": [1,2] } ``` | Field | Type | Required | |-------|------|----------| | `mobile` | string | ✅ | | `name` | string | ✅ | | `gender` / `degree` / `medical_system_code` / `info` | string | ❌ | | `specialties` | integer[] | ❌ | #### Response `201` ```json { "success": true, "data": { "uuid": "..." } } ``` #### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_VALIDATION_002` | 422 | موبایل یا نام خالی | | `ERR_VALIDATION_001` | 422 | `mobile` فرمت معتبر موبایل ایران ندارد (`field: mobile`) | | `ERR_CONFLICT_001` | 409 | این کاربر قبلاً پزشک است | --- ### POST `/api/v1/representation/clinic` افزودن کلینیک توسط نماینده. `representation_id` کلینیک خودکار روی نماینده‌ی کاربر جاری ست می‌شود (مثل createDoctor) تا در لیست‌های scoped دیده شود. #### Request Body ```json { "owner_mobile": "0935...", "name": "کلینیک ...", "telephone": "...", "address": "..." } ``` | Field | Type | Required | |-------|------|----------| | `owner_mobile` | string | ✅ | | `name` | string | ✅ | | `telephone` / `address` / `info` | string | ❌ | #### Response `200` ```json { "success": true, "data": { "uuid": "...", "name": "...", "is_active": true } } ``` #### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_VALIDATION_002` | 422 | موبایل یا نام خالی | | `ERR_VALIDATION_001` | 422 | `owner_mobile` فرمت معتبر موبایل ایران ندارد (`field: owner_mobile`) | --- ### GET `/api/v1/representation/appointments` نوبت‌های همه‌ی پزشکانی که `representation_id` آن‌ها = نماینده‌ی کاربر جاری است (paginated، با شکل آیتمِ یکسان با `/api/v1/admin/appointments`). #### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | پیش‌فرض 1 | | `limit` | integer | ❌ | پیش‌فرض 15، حداکثر 500 | | `status` | string | ❌ | فیلتر وضعیت | | `date` | string (YYYY-MM-DD) | ❌ | فیلتر تاریخِ نوبت | | `search` | string | ❌ | جستجو در موبایل/نام بیمار یا نام پزشک | #### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "patient_name": "...", "patient_mobile": "0912...", "doctor_uuid": "...", "doctor_name": "دکتر ...", "slot_start": 1718000000, "slot_end": 1718001800, "appointment_date": "2025-06-15", "appointment_time": "10:00", "end_time": "10:30", "status": "confirmed", "created_at": 1717900000 } ], "meta": { "totalRecords": 12, "totalPages": 1, "currentPage": 1 } } ``` #### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | کاربر جاری نماینده نیست | --- ### GET `/api/v1/representation/doctors` پزشکانِ ثبت‌شده توسط نماینده‌ی جاری (فقط ردیف‌های `representation_id = نماینده‌ی کاربر جاری`). شکل آیتم یکسان با `GET /api/v1/admin/doctors` است. > **Permission:** `ROLE_REPRESENTATION` — id نماینده از `#[CurrentUser]` تعیین می‌شود، نه از query (نماینده نمی‌تواند داده‌ی نماینده‌ی دیگر را ببیند). #### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | پیش‌فرض 1 | | `limit` | integer | ❌ | پیش‌فرض 15، حداکثر 100 | | `search` | string | ❌ | جستجو در نام یا موبایل پزشک | #### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "id": 12, "name": "دکتر ...", "gender": "man", "degree": "...", "medical_code": "...", "mobile": "0912...", "email": null, "is_active": true, "rate": 3.5, "specialties": [], "profile_image": null, "created_at": "2026-06-18T..." } ], "meta": { "totalRecords": 1, "totalPages": 1, "currentPage": 1 } } ``` #### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | کاربر جاری نماینده نیست | --- ### GET `/api/v1/representation/clinics` کلینیک‌های ثبت‌شده توسط نماینده‌ی جاری (فقط `representation_id = نماینده‌ی کاربر جاری`). شکل آیتم سازگار با `GET /api/v1/admin/clinics`. > **Permission:** `ROLE_REPRESENTATION` — id نماینده از `#[CurrentUser]`. #### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | پیش‌فرض 1 | | `limit` | integer | ❌ | پیش‌فرض 15، حداکثر 100 | | `search` | string | ❌ | جستجو در نام یا تلفن کلینیک | #### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "id": 5, "name": "کلینیک ...", "telephone": "...", "logo": null, "clinic_logo": null, "is_active": true, "doctors_count": 0, "created_at": "2026-06-18T..." } ], "meta": { "totalRecords": 1, "totalPages": 1, "currentPage": 1 } } ``` #### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | کاربر جاری نماینده نیست |