# API ربات CalcGard v1

آدرس پایه:

```text
https://YOUR-DOMAIN/api/v1
```

همه مبلغ‌ها **ریال**، همه زمان‌ها ISO-8601/UTC و همه پاسخ‌ها JSON هستند. API Key را فقط سمت سرور ربات نگه دارید.

## احراز هویت ربات

```http
Authorization: Bearer cg_live_...
Content-Type: application/json
```

## ساخت سفارش

`POST /payments`

```json
{
  "external_id": "order-1001",
  "amount_rial": 1250000,
  "expires_in_minutes": 30,
  "metadata": {
    "telegram_user_id": 123456789
  }
}
```

پاسخ `201`:

```json
{
  "data": {
    "id": 42,
    "external_id": "order-1001",
    "amount_rial": 1250000,
    "status": "pending",
    "expires_at": "2026-09-11T20:30:00+00:00"
  }
}
```

`external_id` باید در هر کسب‌وکار یکتا و شامل حروف انگلیسی، عدد یا `_.:@-` باشد. تکرار آن پاسخ `409` می‌دهد و از ساخت سفارش دوم جلوگیری می‌کند.

## استعلام سفارش

`GET /payments/{external_id}`

وضعیت‌ها:

- `pending`: منتظر واریز
- `paid`: تطبیق قطعی شده
- `cancelled`: توسط ربات لغو شده
- `expired`: مهلت تمام شده
- `manual_review`: برای توسعه آینده رزرو شده؛ در نسخه فعلی ابهام روی تراکنش ثبت می‌شود

## لغو سفارش

`POST /payments/{external_id}/cancel`

فقط سفارش `pending` قابل لغو است.

## وب‌هوک پرداخت

بعد از تطبیق قطعی، پنل این بدنه را به URL تنظیم‌شده می‌فرستد:

```json
{
  "event": "payment.paid",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "created_at": "2026-09-11T20:01:10+00:00",
  "data": {
    "external_id": "order-1001",
    "amount_rial": 1250000,
    "status": "paid",
    "paid_at": "2026-09-11T20:01:09+00:00",
    "metadata": {
      "telegram_user_id": 123456789
    }
  }
}
```

هدرها:

```http
X-CalcGard-Event: 550e8400-e29b-41d4-a716-446655440000
X-CalcGard-Signature: sha256=HEX_HMAC
```

امضا برابر `HMAC-SHA256(raw_request_body, webhook_secret)` است. حتماً امضا را روی **بدنه خام** و با مقایسه constant-time بررسی و `event_id`های پردازش‌شده را ذخیره کنید.

## خطاها

```json
{
  "error": {
    "code": "duplicate_external_id",
    "message": "این شناسه سفارش قبلاً ثبت شده است."
  }
}
```

- `400`: JSON نامعتبر
- `401`: کلید یا امضا نامعتبر
- `402`: لایسنس لازم/منقضی، فقط پس از روشن‌کردن اجرای لایسنس
- `409`: درخواست تکراری یا وضعیت ناسازگار
- `422`: داده نامعتبر
- `429`: محدودیت درخواست

شرح ماشینی API در `web/public/openapi.json` نیز موجود است.
