Files
clinicpro/docs/api/sms.md
T
hamed 5cdcec23a9 feat: enhance staff management and payment gateway features
- Fix national code handling in staff creation and updates to support Persian digits.
- Update ClinicStaff entity to allow longer national codes (up to 15 characters).
- Implement support for clinic secretaries in SecretaryController, allowing creation without a doctor UUID.
- Add a new endpoint to retrieve doctors associated with a clinic for secretary management.
- Improve appointment management by ensuring doctors are selectable even when no appointments exist.
- Extend PatientController to allow secretaries to create patient records if they have the appropriate permissions.
- Introduce a PriceInput component for better price formatting in forms, supporting Persian digits.
- Add a MockGateway for testing payment processes without real transactions.
- Enhance SMS settings management with an approval flow for post-visit text messages, including new fields for pending text and status.
- Update migrations to reflect changes in database schema for national codes and SMS settings.
2026-06-15 11:03:56 +03:30

9.7 KiB

SMS API

Prefix: /api/v1/sms
Providers: kavenegar (default) | rangineh
All send operations are dispatched asynchronously via Symfony Messenger → Redis queue.


POST /api/v1/sms/send

Send a direct SMS message (free text).

Permission: ROLE_ADMIN

Request Body (application/json)

{
  "mobile": "09123456789",
  "message": "سلام، پیام آزمایشی",
  "provider": "kavenegar"
}
Field Type Required Description
mobile string Recipient mobile (09XXXXXXXXX)
message string Message text
provider string "kavenegar" or "rangineh" (default from env)

Response 200

{
  "success": true,
  "data": { "message": "پیامک با موفقیت ارسال شد" }
}

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin
ERR_VALIDATION_001 422 Invalid mobile format

POST /api/v1/sms/send-template

Send an SMS using an approved template.

Permission: ROLE_ADMIN

Request Body (application/json)

{
  "mobile": "09123456789",
  "template_uuid": "tmpl-uuid-...",
  "vars": {
    "name": "دکتر علی احمدی",
    "date": "۱۵ خرداد ۱۴۰۴"
  },
  "provider": "kavenegar"
}
Field Type Required Description
mobile string Recipient mobile
template_uuid string (UUID) UUID of an approved template
vars object Key-value substitutions for template placeholders
provider string Override provider

Response 200

{
  "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 Template not found
ERR_VALIDATION_001 422 Template not approved

POST /api/v1/sms/template

Create a new SMS template.

Permission: ROLE_ADMIN

Request Body (application/json)

{
  "name": "تأیید نوبت",
  "body": "دکتر گرامی ${name}، نوبت شما در تاریخ ${date} تأیید شد.",
  "variables": ["name", "date"]
}
Field Type Required Description
name string Template display name
body string Template text with ${variable} placeholders
variables string[] List of expected variable names

Response 201

{
  "success": true,
  "data": {
    "uuid": "tmpl-uuid-...",
    "name": "تأیید نوبت",
    "body": "دکتر گرامی ${name}...",
    "variables": ["name", "date"],
    "status": "draft",
    "created_at": 1717000000
  }
}

Template Status Values:

Value Description
draft Created, not submitted
pending Submitted for review
approved Ready to use
rejected Rejected

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin
ERR_VALIDATION_002 422 Missing required field

GET /api/v1/sms/template/{uuid}

Get template detail.

Permission: AUTH

Response 200

Template object.

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_NOT_FOUND_001 404 Template not found

PATCH /api/v1/sms/template/{uuid}

Update a template (only allowed in draft or rejected status).

Permission: ROLE_ADMIN

Request Body (application/json)

{
  "name": "تأیید نوبت - ویرایش",
  "body": "نوبت شما در ${date} تأیید شد.",
  "variables": ["date"]
}

All fields optional.

Response 200

Updated template object.

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin
ERR_NOT_FOUND_001 404 Template not found
ERR_SMS_003 422 Template already submitted/approved

POST /api/v1/sms/template/{uuid}/submit

Submit template for admin review (moves status from draft to pending).

Permission: ROLE_ADMIN

Response 200

Updated template with status: "pending".

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin
ERR_NOT_FOUND_001 404 Template not found
ERR_SMS_003 422 Already submitted

DELETE /api/v1/sms/template/{uuid}

Delete a template.

Permission: ROLE_ADMIN

Response 200

{ "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 Template not found

GET /api/v1/admin/sms/templates

List all templates (admin view with all statuses).

Permission: ROLE_ADMIN

Response 200

{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "name": "تأیید نوبت",
      "status": "approved",
      "created_at": 1717000000
    }
  ]
}

POST /api/v1/admin/sms/template/{uuid}/approve

Approve a pending template.

Permission: ROLE_ADMIN

Request Body (application/json)

{
  "note": "تأیید شد",
  "provider_code": "verify_appointment"
}
Field Type Required Description
note string Admin note
provider_code string Provider-side template code

Response 200

Updated template with status: "approved".


POST /api/v1/admin/sms/template/{uuid}/reject

Reject a pending template.

Permission: ROLE_ADMIN

Request Body

{
  "note": "متن قالب نامناسب است"
}
Field Type Required
note string

Response 200

Updated template with status: "rejected".

Errors

Code HTTP Description
ERR_VALIDATION_002 422 Missing note

SMS Wallet

کیف پیامکی — جدا از کیف مالی، فقط برای ارسال پیامک.

GET /api/v1/sms/wallet/balance

Permission: IS_AUTHENTICATED_FULLY

{
  "success": true,
  "data": {
    "balance_rials": 15000,
    "sms_price_rials": 500,
    "estimated_sms_count": 30
  }
}

POST /api/v1/sms/wallet/charge

شارژ کیف پیامکی از طریق درگاه پرداخت.

Permission: IS_AUTHENTICATED_FULLY

{
  "gateway": "mellat",
  "amount_rials": 50000,
  "frontend_address": "https://example.com/sms-wallet"
}

Response 200:

{
  "success": true,
  "data": {
    "payment_uuid": "...",
    "redirect_url": "https://gateway...",
    "order_id": "ORD-..."
  }
}

پس از پرداخت موفق، موجودی کیف خودکار شارژ می‌شود.

GET /api/v1/sms/wallet/logs

تراکنش‌های کیف پیامک (paginated).

Query params: page, limit

{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "type": "credit",
      "amount_rials": 50000,
      "description": "شارژ کیف پیامک",
      "created_at": 1718000000
    }
  ],
  "meta": { "totalRecords": 5, "totalPages": 1, "currentPage": 1 }
}

SMS Settings

GET /api/v1/sms/settings

تنظیمات پیامک entity جاری.

Permission: IS_AUTHENTICATED_FULLY

{
  "success": true,
  "data": {
    "entity_type": "clinic",
    "entity_id": 5,
    "reminder_enabled": true,
    "reminder_hours_before": 2,
    "post_visit_enabled": false,
    "post_visit_text": null,
    "post_visit_text_pending": null,
    "post_visit_text_status": "none",
    "post_visit_text_reject_reason": null,
    "updated_at": 1718000000
  }
}

PATCH /api/v1/sms/settings

Permission: IS_AUTHENTICATED_FULLY

{
  "reminder_enabled": true,
  "reminder_hours_before": 3,
  "post_visit_enabled": true,
  "post_visit_text": "از مراجعه شما سپاسگزاریم"
}

تغییر رفتار post_visit_text: متن ارسال‌شده مستقیماً اعمال نمی‌شود — در فیلد post_visit_text_pending ذخیره می‌شود و وضعیت post_visit_text_status به pending تغییر می‌کند. پس از تأیید ادمین، به post_visit_text منتقل می‌شود.

مقادیر post_visit_text_status: none | pending | approved | rejected


Admin Endpoints

GET /api/v1/admin/sms/settings/review

Permission: ROLE_ADMIN — لیست همه تنظیمات SMS با وضعیت pending

{
  "success": true,
  "data": {
    "data": [
      {
        "id": 3,
        "entity_type": "doctor",
        "entity_id": 7,
        "post_visit_text_pending": "متن در انتظار تأیید",
        "post_visit_text_status": "pending",
        ...
      }
    ]
  }
}

POST /api/v1/admin/sms/settings/{id}/approve

Permission: ROLE_ADMIN — تأیید متن پیامک. post_visit_text_pending به post_visit_text منتقل می‌شود.

POST /api/v1/admin/sms/settings/{id}/reject

Permission: ROLE_ADMIN — رد متن پیامک.

{ "reason": "متن نامناسب است" }

GET /api/v1/admin/sms/wallet-report

Permission: ROLE_ADMIN — لیست همه کیف‌های پیامکی (paginated)