# Admin API > **Prefix:** `/api/v1/admin` > **Permission:** ALL endpoints in this file require `ROLE_ADMIN` > **Headers:** `Authorization: Bearer ` --- ## Dashboard ### GET `/api/v1/admin/dashboard/stats` Get key performance indicators (KPIs) for the dashboard. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "total_users": 1200, "active_doctors": 85, "total_doctors": 92, "total_clinics": 34, "today_appointments": 47, "total_appointments": 8540, "today_payments_count": 30, "today_payments_amount": 15000000, "total_payments_amount": 425000000, "pending_comments": 12, "pending_settlements": 5, "this_month_revenue": 52000000, "this_month_appointments": 620 } } ``` --- ### GET `/api/v1/admin/dashboard/charts` Get chart data for the last 30 days. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "appointments_30d": [ { "date": "2024-06-01", "count": 42 } ], "revenue_30d": [ { "date": "2024-06-01", "amount_rials": 21000000 } ], "appointment_status": { "confirmed": 350, "completed": 180, "cancelled": 45, "pending": 20, "no_show": 25 }, "top_specialties": [ { "name": "قلب و عروق", "count": 120 } ] } } ``` --- ### GET `/api/v1/admin/dashboard/recent` Get recent activity (last 10 of each type). **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "appointments": [ { "uuid": "...", "doctor_title": "دکتر علی احمدی", "patient_name": "محمد رضایی", "slot_start": 1718438400, "status": "confirmed" } ], "payments": [ { "uuid": "...", "amount_rials": 500000, "gateway": "mellat", "status": "paid", "created_at": 1717000000 } ], "users": [ { "uuid": "...", "real_name": "محمد رضایی", "mobile_number": "09...", "roles": ["ROLE_USER"], "created_at": 1717000000 } ] } } ``` --- ## User Management ### GET `/api/v1/admin/users` List all users with pagination and filters. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `search` | string | ❌ | Search by name or mobile | | `role` | string | ❌ | Filter: `ROLE_USER`, `ROLE_DOCTOR`, `ROLE_ADMIN`, etc. | | `status` | string | ❌ | `"active"` or `"inactive"` | | `sort` | string | ❌ | `"created_at"` (default desc) | ### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "real_name": "علی احمدی", "mobile_number": "09123456789", "roles": ["ROLE_USER"], "status": "active", "created_at": 1717000000 } ], "meta": { "totalRecords": 1200, "totalPages": 60, "currentPage": 1 } } ``` --- ### GET `/api/v1/admin/users/{uuid}` Get detailed user info. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "uuid": "...", "real_name": "علی احمدی", "mobile_number": "09123456789", "roles": ["ROLE_USER"], "status": "active", "wallet_balance_rials": 500000, "appointments_count": 5, "created_at": 1717000000 } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | User not found | --- ### GET `/api/v1/admin/users/stats` Get user statistics. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "total": 1200, "active": 1150, "inactive": 50, "admins": 3, "doctors": 92, "patients": 1100 } } ``` --- ### PUT `/api/v1/admin/users/{uuid}` Update user info (name, email, password). **Permission:** `ROLE_ADMIN` ### Request Body (`application/json`) ```json { "real_name": "علی احمدی جدید", "password": "newPassword123" } ``` ### Response `200` Updated user object. --- ### PUT `/api/v1/admin/users/{uuid}/role` Change a user's role. **Permission:** `ROLE_ADMIN` ### Request Body (`application/json`) ```json { "role": "ROLE_DOCTOR" } ``` | Field | Type | Required | Allowed Values | |-------|------|----------|----------------| | `role` | string | ✅ | `ROLE_USER`, `ROLE_DOCTOR`, `ROLE_CLINIC`, `ROLE_SECRETARY`, `ROLE_ADMIN` | ### Response `200` ```json { "success": true, "data": { "message": "نقش کاربر تغییر کرد", "roles": ["ROLE_DOCTOR"] } } ``` --- ### POST `/api/v1/admin/users/{uuid}/status` Toggle user active/inactive status. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "status": "inactive" } } ``` --- ### DELETE `/api/v1/admin/users/{uuid}` Delete a user. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "message": "کاربر حذف شد" } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | User not found | --- ## Doctor Management ### GET `/api/v1/admin/doctors` List all doctors with pagination. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `search` | string | ❌ | Search in title | | `status` | string | ❌ | `"active"` or `"inactive"` | | `gender` | string | ❌ | `"male"` or `"female"` | | `specialty_id` | integer | ❌ | Filter by specialty | | `sort` | string | ❌ | Sort field | ### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "title": "دکتر علی احمدی", "degree": "متخصص", "gender": "male", "doctor_rate": 4.5, "active_doctor_appointment": true } ], "meta": { "totalRecords": 92, "totalPages": 5, "currentPage": 1 } } ``` --- ### GET `/api/v1/admin/doctors/stats` Get doctor statistics. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "total": 92, "active": 85, "inactive": 7, "male": 60, "female": 32, "top_specialty": "قلب و عروق" } } ``` --- ### POST `/api/v1/admin/doctors/{uuid}/status` Toggle doctor active status. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "active": false } } ``` --- ## Clinic Management ### GET `/api/v1/admin/clinics` List all clinics with pagination. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `search` | string | ❌ | Search by clinic name | | `status` | string | ❌ | `"active"` or `"inactive"` | ### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "name": "کلینیک الوند", "city": "تهران", "telephone": "02112345678", "is_active": true, "created_at": 1717000000 } ], "meta": { "totalRecords": 34, "totalPages": 2, "currentPage": 1 } } ``` --- ### PATCH `/api/v1/admin/clinic/{uuid}/status` Toggle clinic active/inactive. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "is_active": false } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | Clinic not found | --- ### DELETE `/api/v1/admin/clinic/{uuid}` Delete a clinic. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": { "message": "کلینیک حذف شد" } } ``` --- ## Appointment Management ### GET `/api/v1/admin/appointments/today-stats` Get appointment statistics for a specific date (defaults to today). **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `date` | string (YYYY-MM-DD) | ❌ | Default: today | ### Response `200` ```json { "success": true, "data": { "total": 47, "completed": 20, "waiting": 18, "cancelled": 9 } } ``` --- ### GET `/api/v1/admin/appointments` List appointments filtered by date and/or doctor. Sorted by `slot_start ASC`. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 15, max: 500 | | `search` | string | ❌ | Search by patient name/mobile or doctor name | | `status` | string | ❌ | Filter by status | | `date` | string (YYYY-MM-DD) | ❌ | Filter by slot date | | `doctor_uuid` | string | ❌ | Filter by doctor UUID | ### Response `200` ```json { "success": true, "data": [ { "uuid": "appt-uuid", "patient_name": "محمد رضایی", "patient_mobile": "09123456789", "doctor_uuid": "doctor-uuid", "doctor_name": "دکتر علی احمدی", "slot_start": 1718438400, "slot_end": 1718439600, "appointment_date": "2025-06-15", "appointment_time": "09:00", "end_time": "09:20", "status": "confirmed", "version": 1, "created_at": "2025-06-14T10:30:00+03:30" } ], "meta": { "totalRecords": 47, "totalPages": 1, "currentPage": 1 } } ``` **Status values:** `pending` | `confirmed` | `completed` | `cancelled_by_doctor` | `cancelled_by_user` | `no_show` | `expired` --- ### POST `/api/v1/admin/appointment` Create a new appointment for a patient. If no user exists with the given mobile, a new user account is created automatically. **Permission:** `ROLE_ADMIN` ### Request Body ```json { "doctor_uuid": "doctor-uuid", "slot_start": 1718438400, "slot_end": 1718439600, "patient_mobile": "09123456789", "patient_name": "علی محمدی", "note": "optional note" } ``` > `patient_mobile` و `patient_name` هر دو اجباری هستند. اگر کاربری با این شماره موبایل نداشته باشیم، یک کاربر جدید با نقش `ROLE_USER` ساخته می‌شود. ### Response `201` ```json { "success": true, "data": { "uuid": "appt-uuid", "slot_start": 1718438400, "slot_end": 1718439600, "status": "pending" } } ``` ### Error Responses | Code | HTTP | Description | |------|------|-------------| | `VALIDATION` | 422 | Missing required fields (doctor_uuid, slot_start, slot_end, patient_mobile, patient_name) | | `DOCTOR_NOT_FOUND` | 404 | Doctor UUID not found | | `SLOT_TAKEN` | 409 | Slot already booked | --- ## Payment Management ### GET `/api/v1/admin/payments` List all payments. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `status` | string | ❌ | `"pending"`, `"paid"`, `"failed"`, `"cancelled"` | ### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "order_id": "CLINICPRO-...", "amount_rials": 500000, "status": "paid", "gateway": "mellat", "created_at": 1717000000 } ], "meta": { "totalRecords": 7800, "totalPages": 390, "currentPage": 1 } } ``` --- ## Settlement Management ### GET `/api/v1/admin/settlements` List all settlement requests. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `status` | string | ❌ | `"pending"`, `"approved"`, `"rejected"` | ### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "user": { "uuid": "...", "real_name": "دکتر علی احمدی" }, "amount_rials": 1000000, "status": "pending", "bank_account": { "bank_name": "بانک ملت", "owner_name": "..." }, "created_at": 1717000000 } ], "meta": { "totalRecords": 45, "totalPages": 3, "currentPage": 1 } } ``` > To approve or reject, use the Settlement API: `POST /api/v1/settlement/{uuid}/approve` or `/reject` --- ## Representation Management ### GET `/api/v1/admin/representations` List all representations. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `search` | string | ❌ | Search by name | | `city_id` | integer | ❌ | Filter by city | ### Response `200` Paginated representation list. --- ## Secretary Management ### GET `/api/v1/admin/secretaries` List all secretaries. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `search` | string | ❌ | Search by mobile | ### Response `200` Paginated secretary list with linked doctor info. --- ## Rating & Comment Management ### GET `/api/v1/admin/rates` List all ratings. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `search` | string | ❌ | Search by doctor/patient | > Ratings are multi-dimensional (five 0–100 dimensions). Each row's `overall` is the mean of the five dimensions (`0–100`) and `score` is that mean on a 0–5 scale (`overall / 20`). --- ### GET `/api/v1/admin/comments` List all comments (all statuses). **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | | `search` | string | ❌ | Search in body | | `status` | string | ❌ | `"pending"`, `"approved"`, `"rejected"` | > To approve/reject comments, use the Rating API: `POST /api/v1/admin/comment/{uuid}/approve` or `/reject` --- ## SMS Management (Admin) ### GET `/api/v1/admin/sms/logs` List SMS send logs. **Permission:** `ROLE_ADMIN` ### Query Parameters | Param | Type | Required | Description | |-------|------|----------|-------------| | `page` | integer | ❌ | Default: 1 | | `limit` | integer | ❌ | Default: 20 | ### Response `200` ```json { "success": true, "data": [ { "id": 1, "mobile": "09123456789", "message": "کد تأیید: 123456", "provider": "kavenegar", "success": true, "created_at": 1717000000 } ], "meta": { "totalRecords": 5000, "totalPages": 250, "currentPage": 1 } } ``` --- ### GET `/api/v1/admin/sms/templates` List all SMS templates. **Permission:** `ROLE_ADMIN` ### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "name": "تأیید نوبت", "status": "approved", "provider_code": "verify_appointment", "created_at": 1717000000 } ] } ``` > To create/approve/reject templates, see [sms.md](sms.md) --- ## Clinic Invitation Management > See [clinic-invitation.md](clinic-invitation.md) for full endpoint details. | Endpoint | Description | |----------|-------------| | `POST /api/v1/admin/clinic/{uuid}/invite-doctor` | Send invitation | | `GET /api/v1/admin/clinic/{uuid}/invitations` | List invitations | | `POST /api/v1/admin/clinic/invitation/{invUuid}/resend` | Resend SMS | | `PATCH /api/v1/admin/clinic/invitation/{invUuid}/status` | Change status | | `DELETE /api/v1/admin/clinic/invitation/{invUuid}` | Delete | --- ## Settings ### GET /api/v1/admin/settings Returns all site configuration values. **Response `200`** ```json { "success": true, "data": { "commission_enabled": "0", "commission_percent": "0", "site_name": "ClinicPro", "support_phone": "", "max_cancel_hours_before": "24", "appointment_reminder_hours": "2", "payment_test_mode": "0", "mellat_terminal_id": "", "mellat_username": "", "mellat_password": "", "sep_terminal_id": "", "sms_provider": "kavenegar", "kavenegar_api_key": "", "kavenegar_sender": "", "sms_price_rials": "500" } } ``` All values are strings. Missing keys return their default values. ### PATCH /api/v1/admin/settings Update one or more settings. Unknown keys are silently ignored. **Request body** (partial update — send only keys to change): ```json { "commission_enabled": "1", "commission_percent": "5", "site_name": "کلینیک‌پرو", "payment_test_mode": "1", "mellat_terminal_id": "12345678", "mellat_username": "user", "mellat_password": "pass", "sep_terminal_id": "87654321", "sms_provider": "kavenegar", "kavenegar_api_key": "your-api-key", "kavenegar_sender": "10008664", "sms_price_rials": "500" } ``` **Response `200`** — same shape as GET, returns all settings after save. **Commission rules:** - `commission_enabled` — `"1"` = active, `"0"` = inactive - `commission_percent` — integer string, `0`–`100` - Commission applies only to regular users (`booked_by = user`); secretaries are exempt **Payment gateway rules:** - `payment_test_mode` — `"1"` = all payments use MockGateway (no real bank calls), `"0"` = real gateways - Gateway credentials (mellat/sep) read from DB first, fallback to env vars if DB value is empty - MockGateway callback: same URL pattern + `&mock=1&ResCode=0&RefId=MOCK-{orderId}` **SMS provider rules:** - `sms_provider` — `"kavenegar"` or `"rangineh"` - Kavenegar API key and sender read from DB first, fallback to env vars `KAVENEGAR_API_KEY`, `KAVENEGAR_SENDER` --- ## Pre-Registration Management ### GET `/api/v1/admin/pre-registrations` List pre-registration requests. **Permission:** `ROLE_ADMIN` **Query params:** | Param | Default | Notes | |-------|---------|-------| | `page` | 1 | | | `limit` | 20 | max 50 | | `status` | `pending` | `pending` \| `approved` \| `rejected` \| `all` | **Response `200`** (paginated): ```json { "success": true, "data": [ { "uuid": "...", "type": "independent_doctor", "name": "دکتر احمدی", "mobile": "09121234567", "info": "متخصص داخلی", "status": "pending", "admin_note": null, "created_at": 1718000000 } ], "meta": { "totalRecords": 5, "totalPages": 1, "currentPage": 1 } } ``` --- ### POST `/api/v1/admin/pre-registrations/{uuid}/approve` Approve a pending request. Creates User + Doctor/Clinic entity based on `type`, resets password, sends SMS. **Permission:** `ROLE_ADMIN` **Response `200`:** ```json { "success": true, "data": { "message": "تأیید شد و اطلاعات ورود ارسال گردید" } } ``` **Error Codes:** | Code | HTTP | Meaning | |------|------|---------| | `NOT_FOUND` | 404 | UUID not found | | `ALREADY_PROCESSED` | 409 | Status is not pending | --- ### POST `/api/v1/admin/pre-registrations/{uuid}/reject` Reject a pending request. **Permission:** `ROLE_ADMIN` **Request body** (optional): ```json { "note": "مدارک ناقص است" } ``` **Response `200`:** ```json { "success": true, "data": { "message": "درخواست رد شد" } } ```