# Settlement & Wallet API > **Prefix:** `/api/v1/wallet`, `/api/v1/settlement` --- ## GET `/api/v1/wallet/balance` Get authenticated user's wallet balance. **Permission:** `AUTH` ### Response `200` ```json { "success": true, "data": { "balance_rials": 2500000, "recent_transactions": [ { "uuid": "...", "type": "credit", "amount_rials": 500000, "balance_after": 2500000, "description": "دریافت از نوبت شماره ...", "created_at": 1717000000 } ] } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | --- ## GET `/api/v1/wallet/transactions` Get wallet transaction history for the authenticated user (paginated, newest first). **Permission:** `AUTH` ### Query Parameters | پارامتر | نوع | توضیح | |---------|-----|-------| | `page` | int | شماره صفحه (پیش‌فرض ۱) | | `limit` | int | تعداد در هر صفحه (پیش‌فرض ۵۰، حداکثر ۱۰۰) | ### Response `200` ```json { "success": true, "data": { "data": [ { "uuid": "...", "type": "credit", "amount_rials": 500000, "balance_after": 2500000, "description": "دریافت از نوبت", "created_at": 1717000000 }, { "uuid": "...", "type": "debit", "amount_rials": 200000, "balance_after": 2300000, "description": "تسویه‌حساب", "created_at": 1716900000 } ], "meta": { "totalRecords": 124, "totalPages": 3, "currentPage": 1 } } } ``` **Transaction Type Values:** | Value | Description | |-------|-------------| | `credit` | Money added to wallet | | `debit` | Money removed from wallet | ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | --- ## POST `/api/v1/settlement` Request a settlement (withdrawal from wallet to bank account). **Permission:** `AUTH` ### Request Body (`application/json`) ```json { "amount_rials": 1000000, "iban_id": "iban-uuid-..." } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `amount_rials` | integer | ✅ | Amount to withdraw (must be ≤ wallet balance) | | `iban_id` | string | ✅ | شناسه‌ی یکی از شباهای **تأییدشده‌ی** نماینده (از `GET /api/v1/representation/me` → `bank_account[].id`) | > شبای انتخابی به‌صورت snapshot (`iban`, `bank_name`, `owner_name`) داخل خود رکورد تسویه ذخیره می‌شود؛ حذف بعدی شبا در پروفایل، این رکورد را تغییر نمی‌دهد. مبلغ همان لحظه‌ی ثبت از کیف‌پول کسر (debit) می‌شود. ### Response `201` ```json { "success": true, "data": { "uuid": "settle-uuid-...", "amount_rials": 1000000, "status": "pending", "bank_account": { "iban": "IR...", "bank_name": "بانک ملت", "owner_name": "علی احمدی" }, "created_at": 1717000000 } } ``` ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_VALIDATION_001` | 422 | مبلغ نامعتبر/بیش از موجودی، یا شبا تأییدنشده/نامعتبر (`field: iban_id`) | | `ERR_VALIDATION_002` | 422 | `iban_id` ارسال نشده (`field: iban_id`) | | `ERR_CONFLICT_001` | 422 | موجودی کافی نیست | --- ## GET `/api/v1/settlement` Get authenticated user's settlement requests (paginated, newest first). **Permission:** `AUTH` > **صفحه‌بندی:** `?page` و `?limit` (پیش‌فرض ۵۰، حداکثر ۱۰۰). پاسخ علاوه بر `data.data` یک `data.meta` (`totalRecords`/`totalPages`/`currentPage`) دارد؛ پاکت قبلی دست‌نخورده است. ### Response `200` ```json { "success": true, "data": [ { "uuid": "...", "amount_rials": 1000000, "status": "pending", "note": null, "created_at": 1717000000, "processed_at": null } ] } ``` **Settlement Status Values:** | Value | Description | |-------|-------------| | `pending` | Awaiting admin review | | `approved` | Approved, payment sent | | `rejected` | Rejected by admin | ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | --- ## GET `/api/v1/settlement/{uuid}` Get a single settlement. **Permission:** `AUTH` — must be the owner or `ROLE_ADMIN` ### Response `200` Settlement object with full details including `bank_account`. ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_FORBIDDEN_001` | 403 | Not the owner | | `ERR_NOT_FOUND_001` | 404 | Settlement not found | --- ## POST `/api/v1/settlement/{uuid}/approve` Approve a settlement request. Marks it as paid and debits the wallet. **Permission:** `ROLE_ADMIN` ### Path Parameters | Param | Type | Description | |-------|------|-------------| | `uuid` | string (UUID) | Settlement UUID | ### Request Body (`application/json`) ```json { "note": "پرداخت شد — شناسه پیگیری: 123456" } ``` | Field | Type | Required | |-------|------|----------| | `note` | string | ❌ | ### Response `200` Updated settlement object with `status: "approved"`. ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_AUTH_006` | 403 | Not admin | | `ERR_NOT_FOUND_001` | 404 | Settlement not found | | `ERR_VALIDATION_001` | 422 | Already processed | --- ## POST `/api/v1/settlement/{uuid}/reject` Reject a settlement request. Returns the amount back to wallet. **Permission:** `ROLE_ADMIN` ### Request Body ```json { "note": "حساب بانکی نادرست است" } ``` | Field | Type | Required | |-------|------|----------| | `note` | string | ✅ | Rejection reason (required) | ### Response `200` Updated settlement object with `status: "rejected"`. ### Errors | Code | HTTP | Description | |------|------|-------------| | `ERR_AUTH_001` | 401 | Missing token | | `ERR_AUTH_006` | 403 | Not admin | | `ERR_NOT_FOUND_001` | 404 | Settlement not found | | `ERR_VALIDATION_002` | 422 | Missing note | --- ## FinancialBreakdown (لاگ مالی) علاوه بر تسویه‌حساب دستی، کیف‌پول نماینده به‌صورت خودکار از طریق `CommissionService` هنگام پرداخت موفقِ نوبت/اشتراک شارژ می‌شود (`WalletTransaction` credit). هر واریز یک ردیف `FinancialBreakdown` ثبت می‌کند که تفکیک کامل تراکنش (ناخالص، هزینه پیامک، مالیات، خالص، درصد و سهم پورسانت، سهم سیستم) را نگه می‌دارد. ثبت idempotent است (بر اساس `payment_id`). گزارش‌ها از طریق `GET /api/v1/admin/financial-breakdowns` و `GET /api/v1/admin/financial-summary` در دسترس‌اند — جزئیات در `docs/api/admin.md`. --- ## رسید پرداخت و ثبت پرداخت نهایی (ROLE_ADMIN) > منطق کیف‌پول: مبلغ هنگام **ثبت درخواست** از کیف‌پول نماینده کسر (reserve/debit) می‌شود؛ **رد** آن را برمی‌گرداند (credit). تأیید و پرداختِ نهایی کیف‌پول را دوباره دست نمی‌زنند (جلوگیری از double-debit). ### POST `/file/upload/clinic_pro/settlement/receipt` آپلود تصویر رسید پرداخت. بدنه = محتوای خام فایل؛ هدر `Content-Disposition: filename="..."`. **Permission:** `ROLE_ADMIN` **Response `200`:** ```json { "success": true, "data": { "uuid": "...", "url": "/uploads/settlements/receipts/2026-06/...", "filename": "...", "filemime": "image/jpeg" } } ``` ### POST `/api/v1/settlement/{uuid}/receipt` ذخیره‌ی رسید پرداخت **بدون** نهایی‌سازی. فقط روی تسویه‌ی **approved**؛ وضعیت تغییر نمی‌کند (همچنان `approved`). پس از این مرحله دکمه‌ی «تکمیل» در پنل فعال می‌شود. **Permission:** `ROLE_ADMIN` **Request Body:** ```json { "receipt": "/uploads/settlements/receipts/2026-06/..." } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `receipt` | string | ✅ | URL رسیدِ آپلودشده | **Response `200`:** آبجکت تسویه (با `receipt` ذخیره‌شده، `status: "approved"`). **Errors:** | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | درخواست یافت نشد | | `ERR_VALIDATION_001` | 422 | تسویه approved نیست | | `ERR_VALIDATION_002` | 422 | `receipt` خالی (`field: receipt`) | ### POST `/api/v1/settlement/{uuid}/paid` **«تکمیل»** — ثبت پرداخت نهایی. فقط روی تسویه‌ی **approved**. وضعیت → `paid` و `receipt` ذخیره می‌شود. کیف‌پول تغییر نمی‌کند (مبلغ هنگام ثبت درخواست کسر شده). پس از تکمیل، آن مبلغ دیگر قابل درخواست تسویه نیست. **Permission:** `ROLE_ADMIN` **Request Body:** ```json { "receipt": "/uploads/settlements/receipts/2026-06/..." } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `receipt` | string | ✅ | URL رسیدِ آپلودشده | **Response `200`:** آبجکت تسویه (شامل `receipt` و `status: "paid"`). **Errors:** | Code | HTTP | Description | |------|------|-------------| | `ERR_NOT_FOUND_001` | 404 | درخواست یافت نشد | | `ERR_VALIDATION_001` | 422 | تسویه approved نیست | | `ERR_VALIDATION_002` | 422 | `receipt` خالی (`field: receipt`) |