# Payment API > **Prefix:** `/api/v1/payment`, `/api/v1/subscription-payment` > **Supported Gateways:** `mellat` (Mellat Bank SOAP) | `sep` (SEP REST) --- ## GET `/api/v1/payment/config` دریافت تنظیمات عمومی پرداخت — برای نمایش وضعیت درگاه آزمایشی در frontend. **Permission:** `IS_AUTHENTICATED_FULLY` ### Response `200` ```json { "success": true, "data": { "test_mode": true } } ``` | Field | Type | Description | |-------|------|-------------| | `test_mode` | boolean | `true` = درگاه آزمایشی فعال است — backend از MockGateway استفاده می‌کند و پول واقعی کسر نمی‌شود | **نکته:** این endpoint هیچ اطلاعات حساسی (terminal_id، password، ...) را expose نمی‌کند. تنها یک boolean برای مصرف frontend است. --- ## GET `/api/v1/my/payments` List the **authenticated user's own** payments (derived from the token — there is no userId in the URL). Used by the public dashboard's transactions tab. **Permission:** `IS_AUTHENTICATED_FULLY` ### Query Parameters | Param | Type | Default | Description | |-------|------|---------|-------------| | `page` | integer | 1 | Page number | | `limit` | integer | 20 | Items per page (max 100) | | `status` | string | — | Optional filter: `pending` / `success` / `failed` / `cancelled` / `refunded` | ### Response `200` (paginated) ```json { "success": true, "data": [ { "uuid": "pay-uuid-...", "order_id": "ORD-84FB82E12A4A45CE", "amount_rials": 590000, "status": "success", "gateway": "mellat", "type": "appointment", "reference_id": "...", "appointment_uuid": "appt-uuid-...", "created_at": 1781521834 } ], "meta": { "totalRecords": 1, "totalPages": 1, "currentPage": 1 } } ``` > Items at `data` (flat array), total at `meta.totalRecords`. Ordered by `created_at` DESC. ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | --- ## POST `/api/v1/payment/appointment` Initiate payment for an appointment. Returns a redirect URL to the payment gateway. **Permission:** `AUTH` — must be the appointment owner (patient) ### Request Body (`application/json`) ```json { "appointment_uuid": "appt-uuid-...", "gateway": "mellat", "frontend_address": "https://myapp.com/payment/result" } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `appointment_uuid` | string (UUID) | ✅ | Appointment to pay for | | `gateway` | string | ✅ | `"mellat"` or `"sep"` | | `frontend_address` | string | ❌ | Redirect URL after payment (overrides default) | ### Response `200` ```json { "success": true, "data": { "payment_uuid": "pay-uuid-...", "redirect_url": "https://bpm.shaparak.ir/pgwchannel/...", "order_id": "CLINICPRO-1717000000-ABC123" } } ``` > **On successful callback** for an appointment payment, the booking is transitioned `pending → confirmed` (its 15-minute `expires_at` is cleared) and a confirmation SMS is dispatched to the patient's mobile. If the booking already lapsed to `expired` before payment confirmed, it is **not** re-confirmed (the transition is rejected) — handle refund out of band. ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_FORBIDDEN_001` | 403 | Not the patient | | `ERR_PAYMENT_003` | 422 | Appointment not in payable state | | `ERR_PAYMENT_002` | 422 | Invalid amount | | `ERR_PAYMENT_001` | 503 | Payment gateway unavailable | --- ## POST `/api/v1/payment/callback/{gateway}` ## GET `/api/v1/payment/callback/{gateway}` Payment gateway callback. Called by the bank after user completes (or cancels) payment. **Permission:** `PUBLIC` — called by the gateway, not the user ### Path Parameters | Param | Type | Description | |-------|------|-------------| | `gateway` | string | `mellat` or `sep` | ### Request (varies by gateway) **Mellat POST fields:** ``` ResCode=0&SaleOrderId=...&SaleReferenceId=...&RefId=... ``` **SEP POST fields:** ``` Status=2&RRN=...&RefNum=...&TerminalId=...&TraceNo=... ``` ### Response - If `ResCode=0` (success): appointment confirmed, redirect to `frontend_address?success=1&uuid=...` - If failed: redirect to `frontend_address?success=0&error=...` ### Notes - On success: appointment status → `confirmed`, wallet credited with doctor's share - Payment record stored with: `order_id`, `amount_rials`, `status`, `gateway`, `ref_id` --- ## POST `/api/v1/subscription-payment` Initiate a subscription / wallet top-up payment (not tied to a specific appointment). **Permission:** `AUTH` ### Request Body ```json { "gateway": "mellat", "amount_rials": 1000000, "frontend_address": "https://myapp.com/wallet/result" } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `gateway` | string | ✅ | `"mellat"` or `"sep"` | | `amount_rials` | integer | ✅ | Amount in Rials (min: 10,000) | | `frontend_address` | string | ❌ | Redirect URL after payment | ### Response `200` ```json { "success": true, "data": { "payment_uuid": "pay-uuid-...", "redirect_url": "https://bpm.shaparak.ir/pgwchannel/...", "order_id": "CLINICPRO-SUB-1717000000-XYZ" } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_PAYMENT_002` | 422 | Invalid amount | | `ERR_PAYMENT_001` | 503 | Gateway unavailable | --- ## POST/GET `/api/v1/subscription-payment/callback/{gateway}` Callback for subscription payments. Same behavior as appointment callback but credits wallet instead. **Permission:** `PUBLIC` --- ## GET `/api/v1/payment/{uuid}` Get payment status and details. **Permission:** `AUTH` — must be the payment owner or `ROLE_ADMIN` ### Path Parameters | Param | Type | Description | |-------|------|-------------| | `uuid` | string (UUID) | Payment UUID | ### Response `200` ```json { "success": true, "data": { "uuid": "pay-uuid-...", "order_id": "CLINICPRO-1717000000-ABC123", "amount_rials": 500000, "status": "paid", "gateway": "mellat", "ref_id": "123456789", "appointment_uuid": "appt-uuid-...", "created_at": 1717000000, "paid_at": 1717000120 } } ``` **Payment Status Values:** | Value | Description | |-------|-------------| | `pending` | Created, not paid yet | | `paid` | Successfully paid | | `failed` | Gateway returned failure | | `cancelled` | User cancelled at gateway | | `refunded` | Refunded | ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_FORBIDDEN_001` | 403 | Not the owner | | `ERR_NOT_FOUND_001` | 404 | Payment not found |