Files
clinicpro/docs/api/secretary.md
T
hamedandClaude Opus 5 4fe0c4f9bf refactor(pricing): make the service the only price source
Price lists, annual tariffs and per-branch price overrides each answered
"what does this service cost?" differently, so a single date could carry
several answers and nobody could say which one was right. Price now lives
only on ServiceItem.price_rials, edited from the services page.

- drop PriceList/PriceListItem, their repositories and the seven
  /api/v1/price-list(s) endpoints; PricingController keeps only quote and
  the appointment price snapshot
- drop Tariff, TariffRepository, TariffService and the two
  /service-items/{uuid}/tariffs endpoints; creating or repricing a service
  no longer upserts a current-year tariff
- drop price_rials from ServiceBranchOverride; the entity stays for its
  duration columns, which DurationCalculator and ServiceSelectionValidator
  still read
- InvoiceService reads the item price directly
- PricingEngine collapses to a single source; breakdown.sources always
  reports service_item, keeping the response contract intact
- remove the price-lists admin page, its route and settings-menu entry, the
  tariff modal and the service detail tariffs tab; useAppointmentInvoice
  moves to its own hook file

Migration drops price_lists, price_list_items, service_tariffs and the
override price column.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 18:00:48 +03:30

30 KiB
Raw Blame History

Secretary API

Prefix: /api/v1/secretary, /api/v1/secretaries

مدل Scope

هر رابطه منشی-پزشک دارای یک scope است که از تداخل بین محیط‌های مختلف جلوگیری می‌کند:

Scope owner_type تعریف‌کننده دسترسی
مطب شخصی doctor خود پزشک فقط نوبت‌ها و داده‌های مطب شخصی
کلینیک clinic مدیر کلینیک فقط نوبت‌ها و داده‌های کلینیک
  • یک منشی می‌تواند هم در مطب شخصی یک دکتر و هم در کلینیک همان دکتر فعال باشد (دو ردیف مجزا)
  • منشی کلینیک می‌تواند به چند دکتر در همان کلینیک متصل باشد
  • یک منشی می‌تواند به همان دکتر در چند کلینیک متفاوت تخصیص یابد (یک ردیف به ازای هر کلینیک). تا پیش از این، کلید یکتا فقط (doctor_id, secretary_id, owner_type) بود و کلینیکِ دوم را تکراری می‌شمرد؛ حالا خودِ محیط هم بخشی از هویت رابطه است
  • scope فعال در runtime از جدول user_active_context خوانده می‌شود — db_uuid به‌همراه db_type که می‌گوید uuid مالِ پزشک است یا کلینیک
  • محدودسازی به پزشکانِ تخصیص‌یافته: منشیِ کلینیک فقط نوبت‌های پزشکانی را می‌بیند/رزرو می‌کند که واقعاً به او تخصیص داده شده‌اند — نه همه‌ی پزشکان کلینیک. لیست نوبت (GET /api/v1/my/appointments) با a.doctor IN (پزشکانِ تخصیص‌یافته) فیلتر می‌شود و گیت رزرو (POST /api/v1/my/appointment) رابطه‌ی فعالِ همان (منشی، کلینیک، پزشک) را چک می‌کند. permission رزرو از همان ردیفِ پزشک خوانده می‌شود

Secretaries are linked to a doctor and have granular permissions controlling what they can do on behalf of the doctor.


POST /api/v1/secretary

Create a secretary for a doctor.

Permission: ROLE_DOCTOR (must own the doctor — creates owner_type='doctor') | ROLE_CLINIC (must have the doctor in its clinic — creates owner_type='clinic') | ROLE_ADMIN

Request Body (application/json)

{
    "doctor_uuid": "550e8400-...",
    "mobile_number": "09123456789",
    "name": "سارا احمدی",
    "national_code": "1234567890",
    "address": "یزد، خیابان تست",
    "password": "secretaryPass123",
    "permissions": {
        "version": 1,
        "resources": {
            "appointments": {
                "view": true,
                "create": true,
                "cancel": false,
                "update_status": true
            },
            "patients": {
                "view": true,
                "create": false,
                "update": false,
                "delete": false
            },
            "payments": {
                "view": true,
                "create": false,
                "update": false,
                "delete": false
            },
            "insurances": {
                "view": true,
                "create": false,
                "update": false,
                "delete": false
            },
            "addresses": {
                "view": true,
                "create": false,
                "update": false,
                "delete": false
            },
            "clinic_info": { "view": true, "update": false },
            "inventory": {
                "view": false,
                "create": false,
                "update": false,
                "delete": false
            },
            "tags": {
                "view": false,
                "create": false,
                "update": false,
                "delete": false
            },
            "services": {
                "view": false,
                "create": false,
                "update": false,
                "delete": false
            },
            "staff":     { "view": false, "create": false, "update": false, "delete": false },
            "discounts": { "view": false, "create": false, "update": false, "delete": false },
            "sms":       { "view": false, "create": false, "update": false, "delete": false },
            "appointment_settings": { "view": false, "update": false },
            "clinic_doctors": { "view": false, "create": false, "update": false, "delete": false },
            "subscription": { "view": false, "create": false }
        }
    }
}
Field Type Required Description
doctor_uuid string (UUID) * Single doctor to assign (legacy/doctor flow)
doctor_uuids string[] (UUID) * Clinic only — assign one secretary to several clinic doctors at once. When present (non-empty) and caller is ROLE_CLINIC, this multi-doctor path is used instead of doctor_uuid
mobile_number string Secretary's login mobile. Persian/Arabic digits are accepted and normalized server-side — see README → Persian digit normalization
name string Full name (نام + نام خانوادگی) → user_name
national_code string کد ملی منشی (nullable). Persian/Arabic digits accepted and normalized
address string آدرس منشی (nullable)
password string Initial password (auto-generated if omitted)
permissions object Permission set (see structure below)

* یکی از doctor_uuid (تک‌پزشکی) یا doctor_uuids (چند‌پزشکیِ کلینیک) الزامی است.

پاسخِ حالت چند‌پزشکی (doctor_uuids + ROLE_CLINIC) — 201:

{
  "success": true,
  "data": {
    "secretary_uuid": "550e8400-...",
    "created": [ { "uuid": "...", "secretary_uuid": "...", "doctor_uuid": "...", "...": "..." } ],
    "skipped_duplicate": [],
    "skipped_limit": [],
    "skipped_not_in_clinic": []
  }
}
  • created: ردیف‌های تازه‌ساخته/فعال‌شده · skipped_duplicate: قبلاً متصل بوده · skipped_limit: سقفِ پلنِ آن پزشک پر است · skipped_not_in_clinic: پزشک عضو کلینیک نیست. حلقه اتمیک است و بقیه‌ی پزشکان ادامه می‌یابند.

Permissions Structure:

مجموعهٔ منابع (resources) بر اساس صفحات و ماژول‌های در دسترسِ منشی است: appointments, patients, payments, insurances, addresses, clinic_info, inventory, tags, services, staff, discounts, sms, appointment_settings, clinic_doctors, subscription. منبعِ subscription فقط view/create دارد. mergePermissions هر منبع/اکشن ارسال‌شده را deep-merge می‌کند. منابعِ inventory, tags, services, staff, discounts, sms, appointment_settings, clinic_doctors به‌صورت پیش‌فرض همه false‌اند (default-deny)؛ بقیه طبق DEFAULT_PERMISSIONS. منبعِ appointment_settings فقط view/update دارد. منبعِ clinic_doctors فقط در حالت کلینیک معنا دارد (پزشک مستقل نه toggle نه منو).

اعمال (enforcement): همهٔ منابع در بک‌اند enforce می‌شوند، نه فقط appointments. منبعِ حقیقت، ستون JSON permission روی ردیفِ فعالِ DoctorSecretary در محیطِ فعالِ کاربر (UserActiveContext.db_uuid) است؛ نقطهٔ مرکزی App\Secretary\Security\SecretaryAccessChecker (can / canOrNonSecretary / denyUnlessGranted). نبودِ مجوز → 403 ERR_FORBIDDEN_001. نقشه:

Resource Enforced in Action → endpoint
appointments AppointmentAccessChecker, MyAppointmentsController, DashboardController view/create/cancel/update_status
patients PatientController (خواندن‌ها via scope() → بدون view هیچ پرونده‌ای؛ افزودن/ویرایشِ زیرآیتم‌ها = update؛ حذفِ یادداشت/سند/رکورد/تماس/پیام = delete — جدا از update) view/create/update/delete
payments PaymentController::myPayments, PaymentMethodController (bank/pos), PatientController (کیف‌پول + پرداختِ جلسه) view/create/update/delete
insurances InsuranceController (insurance-pricing, tenant-insurances, service-coverage, doctor-insurance) view/create/update/delete
inventory InventoryController (items + packages) view/create/update/delete
tags TenantTagController (لیست با tags.view یا patients.view؛ نوشتن‌ها با tags.*) view/create/update/delete
services ClinicServiceController (sections + items). owner از محیطِ فعال با SecretaryAccessChecker::resolveOwnerEntity حل می‌شود چون EntityContextResolver منشی را نمی‌شناسد. گیتِ services.* پیش از گیتِ اشتراک اجرا می‌شود view/create/update/delete
staff StaffController (resolveEntity منشی‌آگاه) view/create/update/delete
discounts DiscountController (CRUD؛ suggestions جزو flowِ جلسه است و با discounts گِیت نمی‌شود) view/create/update/delete
sms SmsWalletController (balance/charge/logs/settings). endpointهای admin (قالب/ارسال) همچنان ROLE_ADMIN view/create/update
appointment_settings AppointmentSettingsController::denyDoctorAccessSecretaryAccessChecker::canForDoctor (اسکوپِ پزشکِ تخصیص‌یافته + توگل). clinic_uuid برای محیطِ کلینیک لازم است view/update
clinic_doctors (فقط کلینیک) ClinicController::detachDoctor (delete)، ClinicDoctorPermissionController (view/update)، ClinicInvitationController (create/view/update/delete) via SecretaryAccessChecker::canForClinic view/create/update/delete
subscription SubscriptionController::my (view) و trial (create)، PaymentController::initiateSubscription (create). resolveEntity از قبل منشی‌آگاه است view/create

نقش‌های غیرمنشی (ROLE_CLINIC/ROLE_DOCTOR/ROLE_ADMIN) از این چک عبور می‌کنند (canOrNonSecretary برایشان true). منشیِ بدون رابطهٔ فعال/context هیچ مجوزی ندارد → همه‌چیز 403.

{
    "version": 1,
    "resources": {
        "appointments": {
            "view": true, // Can view appointments list
            "create": true, // Can book appointments
            "cancel": false, // Can cancel appointments
            "update_status": true // Can mark as completed/no_show
        },
        "patients": {
            "view": true,
            "create": false,
            "update": false,
            "delete": false
        },
        "payments": {
            "view": true,
            "create": false,
            "update": false,
            "delete": false
        },
        "insurances": {
            "view": true,
            "create": false,
            "update": false,
            "delete": false
        },
        "addresses": {
            "view": true,
            "create": false,
            "update": false,
            "delete": false
        },
        "clinic_info": {
            "view": true,
            "update": false
        },
        "inventory": {
            "view": false, // انبار: مشاهده
            "create": false, // ایجاد کالا/بسته
            "update": false,
            "delete": false
        },
        "tags": {
            "view": false, // تگ‌ها؛ لیست با tags.view یا patients.view
            "create": false,
            "update": false,
            "delete": false
        }
    }
}

Response 201

{
  "success": true,
  "data": {
    "uuid": "sec-uuid-...",
    "user_name": "علی محمدی",
    "mobile_number": "09123456789",
    "doctor_name": "احمد رضایی",
    "doctor_uuid": "...",
    "owner_type": "doctor",
    "clinic_uuid": null,
    "is_active": true,
    "national_code": "1234567890",
    "address": "یزد، خیابان تست",
    "permissions": { ... },
    "created_at": 1717000000
  }
}

مقادیر owner_type:

مقدار معنی
doctor منشی توسط خود دکتر تعریف شده — فقط مطب شخصی
clinic منشی توسط مدیر کلینیک تعریف شده — فقط کلینیک

پیامک خوش‌آمد: پس از ساخت موفق منشی، یک پیامک به‌صورت async به mobile_number منشی ارسال می‌شود (تگ secretary). متن از قالب ویرایش‌پذیر DB می‌آید (fallback به پیش‌فرض) و placeholderهای {owner} (نام دکتر یا کلینیک بسته به owner_type{username} (موبایل منشی) و {link} (لینک ورود) را جایگزین می‌کند. ویرایش متن از PATCH /api/v1/admin/sms/messages/secretary — رجوع به sms.md.

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not the doctor owner / clinic owner / admin
ERR_NOT_FOUND_001 404 Doctor not found
ERR_CONFLICT_001 409 Secretary already added for this doctor in this same environment — همان منشی برای همان پزشک در کلینیکِ دیگر ۴۰۹ نمی‌گیرد
ERR_SECRETARY_001 422 Plan limit for secretaries reached

GET /api/v1/secretary/{uuid}

Get secretary detail.

Permission: AUTH — must be the linked doctor or ROLE_ADMIN

Path Parameters

Param Type Description
uuid string (UUID) Secretary UUID

Response 200

{
  "success": true,
  "data": {
    "uuid": "...",
    "mobile_number": "09123456789",
    "active": true,
    "permissions": { ... },
    "doctor": { "uuid": "...", "title": "علی احمدی" },
    "created_at": 1717000000
  }
}

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_FORBIDDEN_001 403 Not authorized
ERR_NOT_FOUND_001 404 Secretary not found

PATCH /api/v1/secretary/{uuid}

Update secretary active status, profile fields (name/national_code/address), or permissions. تمام فیلدها اختیاری‌اند و فقط موارد ارسال‌شده اعمال می‌شوند.

Permission: ROLE_DOCTOR — must be the linked doctor

Request Body (application/json)

{
    "active": false,
    "name": "نام جدید",
    "national_code": "9999999999",
    "address": "آدرس جدید",
    "permissions": {
        "version": 1,
        "resources": {
            "appointments": {
                "view": true,
                "create": false,
                "cancel": false,
                "update_status": false
            }
        }
    }
}
Field Type Required Description
active boolean Enable/disable secretary
name string به‌روزرسانی نام کامل منشی (user_name)
national_code string به‌روزرسانی کد ملی (nullable)
address string به‌روزرسانی آدرس (nullable)
permissions object New permissions object (deep-merged)

Response 200

Updated secretary object.

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_FORBIDDEN_001 403 Not the linked doctor
ERR_NOT_FOUND_001 404 Secretary not found

DELETE /api/v1/secretary/{uuid}

Delete a secretary.

Permission: ROLE_DOCTOR — must be the linked doctor

Response 200

{ "success": true, "data": { "message": "منشی حذف شد" } }

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_FORBIDDEN_001 403 Not the linked doctor
ERR_NOT_FOUND_001 404 Secretary not found

GET /api/v1/secretaries/{doctorUuid}

Get all secretaries for a specific doctor.

Permission: ROLE_DOCTOR (must own doctor) | ROLE_CLINIC (must have doctor in clinic) | ROLE_ADMIN

Path Parameters

Param Type Description
doctorUuid string (UUID) Doctor UUID

Response 200

{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "user_name": "علی محمدی",
      "mobile_number": "09...",
      "doctor_name": "احمد رضایی",
      "doctor_uuid": "...",
      "is_active": true,
      "permissions": { ... },
      "created_at": 1717000000
    }
  ]
}

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_FORBIDDEN_001 403 Not authorized
ERR_NOT_FOUND_001 404 Doctor not found

GET /api/v1/secretaries/clinic/{clinicUuid}

Get all secretaries across all doctors of a clinic.

Permission: ROLE_CLINIC (must own clinic) | ROLE_ADMIN

Path Parameters

Param Type Description
clinicUuid string (UUID) Clinic UUID

Response 200

{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "secretary_uuid": "...",
      "user_name": "علی محمدی",
      "mobile_number": "09...",
      "doctor_name": "احمد رضایی",
      "doctor_uuid": "...",
      "is_active": true,
      "permissions": { ... },
      "created_at": 1717000000
    }
  ]
}

Notes

  • این endpoint فقط منشی های را برمی‌گرداند که با owner_type='clinic' تعریف شده‌اند
  • منشی های که خود دکتر (با owner_type='doctor') تعریف کرده از این لیست مخفی هستند
  • یک منشی می‌تواند به چند دکتر در همان کلینیک متصل باشد — در لیست چندبار ظاهر می‌شود (یک ردیف به ازای هر دکتر). برای گروه‌بندی «یک منشی، چند پزشک» از secretary_uuid (uuid کاربرِ منشی) استفاده کنید

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_FORBIDDEN_001 403 Not clinic owner
ERR_NOT_FOUND_001 404 Clinic not found

PUT /api/v1/secretaries/clinic/{clinicUuid}/doctors

هم‌گام‌سازی مجموعه‌ی پزشکانِ یک منشیِ کلینیک (owner_type='clinic'): پزشکانِ خواسته‌شده افزوده/فعال و بقیه غیرفعال می‌شوند. برای «افزودن/حذف پزشک از یک منشی موجود» بدون تغییر ساختاری.

ردیف‌های تازه‌ساخته‌شده national_code، address و permissions را از ردیف‌های موجودِ همان منشی کپی می‌کنند تا پروفایل یک شخص روی همه‌ی پزشکانش یکسان بماند. اگر همراه با ویرایش پروفایل صدا زده می‌شود، اول PATCH /api/v1/secretary/{uuid} روی ردیف‌های موجود و بعد این اندپوینت را فراخوانی کنید.

Permission: ROLE_CLINIC (must own clinic) | ROLE_ADMIN

Path Parameters

Param Type Description
clinicUuid string (UUID) Clinic UUID

Request Body (application/json)

{
  "secretary_uuid": "550e8400-...",
  "doctor_uuids": ["uuid-doc-a", "uuid-doc-b"]
}
Field Type Required Description
secretary_uuid string (UUID) uuid کاربرِ منشی (همان secretary_uuid خروجی لیست/ساخت)
doctor_uuids string[] (UUID) مجموعه‌ی نهاییِ پزشکان؛ نبودها افزوده، اضافه‌ها غیرفعال می‌شوند

Response 200

{
  "success": true,
  "data": {
    "added": 1,
    "removed": 1,
    "skipped_limit": [],
    "skipped_not_in_clinic": []
  }
}
Field Type Description
added int تعداد ردیف‌های افزوده/فعال‌شده
removed int تعداد ردیف‌های غیرفعال‌شده
skipped_limit string[] uuid پزشکانی که به سقفِ پلن رسیده‌اند (نادیده گرفته)
skipped_not_in_clinic string[] uuid پزشکانی که عضو این کلینیک نیستند

Errors

Code HTTP Description
ERR_AUTH_006 403 Not clinic owner nor admin
ERR_VALIDATION_001 422 secretary_uuid/doctor_uuids missing
ERR_VALIDATION_002 404 Clinic or secretary not found

محدودیت پنل اشتراکی

تعداد منشی‌های مجاز بر اساس پنل فعال doctor تعیین می‌شود:

پنل حداکثر منشی
Free (بدون اشتراک) ۱
Basic ۳
Professional ۱۰

اگر تعداد منشی‌های فعال به حد مجاز رسیده باشد، ایجاد منشی جدید خطای زیر را برمی‌گرداند:

{
    "success": false,
    "errors": [
        {
            "code": "ERR_SECRETARY_001",
            "message": "پلن فعلی اجازه منشی بیشتر را نمی‌دهد"
        }
    ]
}

برای افزایش محدودیت، باید پنل را از POST /api/v1/subscription/trial (تریال) یا POST /api/v1/subscription-payment (پرداخت) ارتقاء داد.


سهم منشی از نوبت‌های آنلاین (درآمد و تسویه)

ادمین می‌تواند برای هر رابطهٔ منشی–پزشک/کلینیک، محاسبهٔ درآمد از نوبت‌های آنلاین را فعال کند و درصد بدهد (admin.md). سهم از مبلغ خالص نوبت گرفته می‌شود: ابتدا هزینهٔ پنل پیامک، بعد مالیات، سپس درصدِ منشی روی «خالصِ پس از مالیات» — همان مبنایی که پورسانت نماینده از آن محاسبه می‌شود (settlement.md).

«آنلاین» یعنی چه؟ تقسیم مالی تنها پس از پرداخت موفق درگاه (PaymentManager) اجرا می‌شود؛ نوبتی که در پنل ثبت و «قطعی» می‌شود از این مسیر عبور نمی‌کند و سهمی نمی‌سازد. انتساب بر پایهٔ محیط نوبت است: کلینیکِ نوبت، وگرنه خودِ پزشک. اگر چند منشیِ سهم‌بر وجود داشته باشد، هر کدام درصد خودش را می‌گیرد (تقسیم نمی‌شود)؛ اگر مجموع درصدها از ۱۰۰ بگذرد به نسبت کلیپ می‌شود و هشدار لاگ می‌گردد تا سهم سیستم منفی نشود.

سهم هر منشی در جدول secretary_earnings ثبت و به‌صورت اعتبار در کیف پول همان کاربر منظور می‌شود؛ برداشت از طریق POST /api/v1/settlement انجام می‌گیرد.


GET /api/v1/secretary/earnings/summary

خلاصهٔ درآمد منشیِ جاری.

Permission: AUTH (کاربر منشی)

Response 200

{
  "success": true,
  "data": {
    "data": {
      "enabled": true,
      "share_percent": 5,
      "relations": [
        { "relation_uuid": "rel-…", "doctor_name": "دکتر احمدی", "clinic_name": null, "share_percent": 5 }
      ],
      "today_rials": 500000,
      "this_month_rials": 3000000,
      "total_rials": 9000000,
      "appointments_count": 4,
      "wallet_balance_rials": 9000000
    }
  }
}
فیلد توضیح
enabled false یعنی هیچ رابطهٔ فعالی با سهمِ روشن ندارد؛ پنل پیام «فعال نیست» نشان می‌دهد (خطا نمی‌دهیم)
share_percent درصد اولین رابطهٔ سهم‌بر؛ تفکیک کامل در relations
today_rials از نیمه‌شب امروز
this_month_rials ۳۰ روز گذشته
wallet_balance_rials موجودی کیف پول همان کاربر (مبنای تسویه)

GET /api/v1/secretary/earnings/report

گزارش سطر-به-سطر سهم منشی (paginated).

Permission: AUTH (کاربر منشی)

Query Parameters

Param Type Required Description
page integer پیش‌فرض ۱
limit integer پیش‌فرض ۱۵، حداکثر ۱۰۰
from integer Unix — از تاریخ
to integer Unix — تا تاریخ

Response 200

{
  "success": true,
  "data": [
    {
      "uuid": "earning-uuid-…",
      "appointment_uuid": "appt-uuid-…",
      "doctor_name": "دکتر احمدی",
      "gross_rials": 10000000,
      "sms_fee_rials": 1000000,
      "tax_rials": 818182,
      "net_after_tax_rials": 8181818,
      "share_percent": 5,
      "share_rials": 409091,
      "created_at": 1700000000
    }
  ],
  "meta": { "totalRecords": 1, "totalPages": 1, "currentPage": 1 }
}

منشیِ بدون سهم، پاسخ 200 با آرایهٔ خالی می‌گیرد (نه 403).


GET /api/v1/secretary/me

پروفایل منشیِ جاری: رابطه‌ها با تنظیمات سهم + شماره‌های شبا.

Permission: AUTH (کاربر منشی)

Response 200

{
  "success": true,
  "data": {
    "data": {
      "full_name": "زهرا رضایی",
      "mobile": "0912…",
      "bank_account": [
        { "id": "iban-uuid-…", "iban": "IR…", "bank_name": "ملی", "owner_name": null, "verified": false, "created_at": 1700000000 }
      ],
      "relations": [
        { "relation_uuid": "rel-…", "doctor_name": "دکتر احمدی", "clinic_name": null, "online_share_enabled": true, "online_share_percent": 5 }
      ]
    }
  }
}

POST /api/v1/secretary/iban

افزودن شماره شبا (حداکثر ۲) به پروفایل کاربرِ منشی — مثل پنل نماینده.

Permission: AUTH (کاربر منشی)

Request Body (application/json)

{ "iban": "IR123456789012345678901234", "bank_name": "ملی", "owner_name": "زهرا رضایی" }
Field Type Required Description
iban string الگوی IR + ۲۴ رقم (فاصله‌ها حذف می‌شود)
bank_name string نام بانک
owner_name string نام صاحب حساب

Response 201

{ "success": true, "data": { "data": { "bank_account": [ { "id": "…", "iban": "IR…", "verified": false } ] } } }

verified همیشه false ثبت می‌شود؛ تأیید فقط از سمت ادمین انجام می‌گیرد و تسویه تنها با شبای تأییدشده مجاز است.

Errors

Code HTTP Description
ERR_VALIDATION_001 422 شبا نامعتبر (field: iban)
ERR_VALIDATION_001 422 بیش از دو شبا (field: iban)

DELETE /api/v1/secretary/iban/{id}

حذف یکی از شباهای منشیِ جاری.

Permission: AUTH (کاربر منشی)

Response 200

{ success, data: { data: { bank_account: [...] } } }

Errors

Code HTTP Description
ERR_NOT_FOUND_001 404 پروفایل/شبا یافت نشد

کیف پول و تسویه اندپوینت اختصاصی ندارند: GET /api/v1/wallet/balance، GET /api/v1/wallet/transactions و POST /api/v1/settlement کاربر-محورند (settlement.md).