Files
clinicpro/docs/api
hamedandClaude Opus 5 5c754244f2 feat(admin): finish the screens that were stopping one step short
Five places where the data existed and the screen did not use it.

Booking a whole course had no button because it needs a doctor and the course
does not carry one — each session can be with a different doctor. The page now
asks for the doctor the same way the resource booking page does, and the button
explains that it is all-or-nothing before it is pressed.

A course whose package does not cover the remaining sessions is still valid —
the rest is simply charged normally — but nobody was told. The course response
carries package_balance and the shortfall, and the page warns. Before session
six, not during it.

The credit ledger already returned who recorded a row and which appointment it
belonged to, and showed neither. An adjustable ledger without the name of the
person who adjusted it is half an audit trail.

Version history printed a JSON blob of each version's effects, which does not
answer the question anyone actually has: what changed? It now diffs each
version against the previous one, field by field, and says so plainly when a
version changed nothing meaningful.

A resource with no calendar showed "—" for utilization. Null means undefined,
not zero, and the next step is always the same: set up the calendar. It is a
link now. The report range also accepts a custom from/to, kept in the URL like
the rest.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 15:07:27 +03:30
..

ClinicPro — API Documentation Index

Base URL: https://clinic-pro.ddev.site
API Prefix: /api/v1
Swagger UI: https://clinic-pro.ddev.site/api/doc — user: admin / pass: clinic123


Authentication

All protected endpoints require:

Authorization: Bearer <JWT_TOKEN>
Role Description
PUBLIC No token required
AUTH Any valid JWT
ROLE_ADMIN Admin user
ROLE_DOCTOR Doctor user
ROLE_CLINIC Clinic owner
ROLE_SECRETARY Secretary

Standard Response Envelope

// Success
{ "success": true, "data": { ... } }

// Paginated
{ "success": true, "data": [...], "meta": { "totalRecords": 100, "totalPages": 5, "currentPage": 1, "limit": 20 } }

// Error
{ "success": false, "data": null, "errors": [{ "code": "ERR_XXX_000", "message": "..." }] }

meta.limit اندازهٔ صفحهٔ واقعاً اعمال‌شده است. ریپازیتوری‌ها limit درخواستی را به سقف خودشان کاهش می‌دهند (مثلاً لیست پزشکان: سقف ۵۰)، پس برای پیمایش کامل به meta.totalPages تکیه کن — نه به این فرض که «تعداد آیتم کمتر از limit درخواستی یعنی صفحهٔ آخر».


Persian digit normalization (global)

Persian (۰) and Arabic (٠) digits sent in numeric request fields are translated to Latin server-side, before the controller runssrc/Shared/EventSubscriber/NumericFieldNormalizerSubscriber.php. Every client benefits: the React admin panel, nobat724_front, and clinic-pro-tauri.

Applies to POST / PUT / PATCH requests under /api/v1/ with a JSON body, recursively through nested arrays.

Normalized keys:

mobile, mobile_number, telephone, phone, notification_mobile,
national_code, postal_code,
card_number, account_number, sheba, shaba, iban,
price_rials, amount_rials, amount, free_visit_price_rials,
insurance_price_rials, patient_share_rials, visit_price_rials,
duration_minutes, duration, commission_percent, coverage,
coverage_percent, franchise, ceiling, tax_percent,
base_insurance_discount_percent, supplementary_discount_percent

Only digits are translated — no characters are stripped, so IR in a sheba and - in a landline survive. Non-string values (int, bool, null) and keys outside the list are untouched, so a name like منشی شماره ۲ keeps its Persian digit.

// request
{ "mobile_number": "۰۹۱۲۳۴۵۶۷۸۹", "national_code": "۰۰۱۲۳۴۵۶۷۸", "name": "منشی شماره ۲" }

// what the controller sees
{ "mobile_number": "09123456789", "national_code": "0012345678", "name": "منشی شماره ۲" }

Adding a new numeric field to any endpoint? Add its key to NUMERIC_KEYS in the subscriber, otherwise Persian digits reach the database.


Modules

File Domain Endpoints
auth.md Authentication — OTP, Login, JWT 8
doctor.md Doctor profile & addresses 11
clinic.md Clinics 7
clinic-invitation.md Doctor invitations to clinics 8
branch.md Branches (= addresses), working hours, rooms 8
resource.md Resources, types, skills, pools 16
resource-calendar.md Resource calendars, exceptions, national holidays 9
appointment-plan.md Appointment segments and plan preview 3
appointment-availability.md Multi-resource availability search 2
appointment-booking.md Holds, confirmation and multi-resource occupancy 4
pricing.md Date-ranged price lists and appointment invoices 8
appointment.md Appointments & slot booking 6
appointment-settings.md Weekly schedule, date overrides, holidays 14
payment.md Payments (Mellat / Sep) 5
settlement.md Wallet & settlement requests 7
rating.md Ratings, comments, likes 9
secretary.md Doctor secretaries 5
representation.md Representations (agents) 6
sms.md SMS send & templates 10
blog.md Blog posts 6
specialty.md Medical specialties 5
insurance.md Insurances & doctor-insurance links 10
doctor-service.md Doctor services 5
tag.md Blog tags 5
location.md Provinces & cities 10
user-profile.md User medical profile 4
admin.md Admin dashboard & management 25+

Error Code Reference

Code Message (FA) HTTP
ERR_AUTH_001 توکن JWT منقضی یا نامعتبر 401
ERR_AUTH_002 کد OTP نامعتبر 401
ERR_AUTH_003 کد OTP منقضی شده 401
ERR_AUTH_004 تعداد تلاش‌های OTP به حد مجاز رسیده 429
ERR_AUTH_005 نام کاربری یا رمز عبور اشتباه 401
ERR_AUTH_006 دسترسی ممنوع 403
ERR_VALIDATION_001 ورودی نامعتبر 422
ERR_VALIDATION_002 فیلد الزامی وارد نشده 422
ERR_NOT_FOUND_001 منبع درخواستی یافت نشد 404
ERR_CONFLICT_001 تداخل: منبع در حال استفاده 409
ERR_FORBIDDEN_001 دسترسی به این منبع مجاز نیست 403
ERR_PAYMENT_001 درگاه پرداخت در دسترس نیست 503
ERR_PAYMENT_002 مبلغ پرداخت نامعتبر 422
ERR_PAYMENT_003 وضعیت نوبت برای پرداخت مناسب نیست 422
ERR_FILE_001 فرمت فایل مجاز نیست 422
ERR_SMS_003 تمپلیت قبلاً ارسال شده 422
ERR_SECRETARY_001 پلن فعلی اجازه منشی بیشتر نمی‌دهد 422
ERR_RATE_LIMIT_001 درخواست‌های زیاد، بعداً تلاش کنید 429