رایگان/api/v1

وب‌هوک‌ها

اعلان HTTPS رایگان هنگام به‌روزرسانی جداول کدال، صندوق یا گزارش‌ها — با JWT؛ امضای HMAC.

اعلان‌های HTTPS خروجی وقتی جداول همگام‌سازی کدال، صندوق یا گزارش‌ها به‌روز می‌شوند. رایگان است (بدون کسر از کیف پول). برای دریافت ردیف‌ها همچنان باید GET /external/codal/data، GET /external/funds/data یا GET /external/reports/data را با کلید API (مثلاً updated_at_start) فراخوانی کنید — آن فراخوانی‌ها هزینه‌دارند.

Auth: JWT Authorization: Bearer <access_token> (همان کیف پول و کلیدها)

ItemValue
حداکثر endpoint فعال۳ به‌ازای هر کاربر (EXTERNAL_API_WEBHOOK_MAX_PER_USER)
رویدادها (v1)codal.table.updated, funds.table.updated, reports.table.updated
غیرفعال‌سازی خودکارپس از ۲۰ شکست تحویل متوالی

POST/api/v1/external/webhooks

ساخت endpoint جدید.

Body:

نمونه
{
  "url": "https://partner.example.com/hooks/codal",
  "events": ["codal.table.updated", "funds.table.updated", "reports.table.updated"],
  "description": "Prod ingest"
}

پاسخ شامل signing_secret یک‌بار است (امن نگه دارید). در لیست بعدی فقط secret_last4 نمایش داده می‌شود. URL باید HTTPS باشد.

Example:

نمونه
curl -X POST "https://api.codal724.ir/api/v1/external/webhooks" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d "{\"url\":\"https://partner.example.com/hooks/codal\",\"events\":[\"codal.table.updated\",\"funds.table.updated\",\"reports.table.updated\"]}"

مدیریت endpoint

همه مسیرها زیر /api/v1/external و با JWT.

MethodPathتوضیح
GET/webhooksفهرست endpointها
PATCH/webhooks/{id}فقط جایگزینی events. signing_secret را عوض نمی‌کند. URL در ساخت باید HTTPS باشد
DELETE/webhooks/{id}حذف
POST/webhooks/{id}/rotate-secretsigning_secret جدید (یک‌بار)
POST/webhooks/{id}/testرویداد آزمایشی در صف — اگر اشتراک کدال وجود داشته باشد همان را ترجیح می‌دهد؛ تست تحویل گزارش‌ها نیست
GET/webhooks/{id}/deliveriesگزارش تحویل‌های اخیر

برای اضافه کردن reports.table.updated نیازی به حذف/ساخت مجدد یا rotate-secret نیست؛ PATCH کافی است.

PATCH body:

نمونه
{
  "events": ["codal.table.updated", "funds.table.updated", "reports.table.updated"]
}

قرارداد تحویل (Delivery)

POST به URL شریک با بدنه JSON. فیلدهای data همیشه: service, table_name, last_updated_at.

نمونه
{
  "id": "…",
  "type": "codal.table.updated",
  "created_at": "…",
  "api_version": "2026-07-25",
  "data": {
    "service": "codal",
    "table_name": "income_statement",
    "last_updated_at": "…"
  }
}

فقط برای گزارش‌ها، فیلدهای اضافه (اختیاری):

typedata.table_nameExtra
reports.table.updatedsymbol_reportsoptional symbol
reports.table.updatedmarket_daily_reportsoptional trade_date (YYYY-MM-DD)
نمونه
{
  "id": "…",
  "type": "reports.table.updated",
  "created_at": "…",
  "api_version": "2026-07-25",
  "data": {
    "service": "reports",
    "table_name": "symbol_reports",
    "last_updated_at": "…",
    "symbol": "فولاد"
  }
}

table_name ناشناخته را با HTTP 200 نادیده بگیرید (نه 4xx) تا از retry و غیرفعال‌سازی خودکار جلوگیری شود.

Headers:

HeaderMeaning
X-Webhook-Idهمان id بدنه (dedupe)
X-Webhook-TimestampUnix seconds
X-Webhook-Signaturesha256=<hex> از {timestamp}.{raw_body} با signing secret

Verify (Node.js):

نمونه
import crypto from "crypto";

export function verifyWebhook(
  secret: string,
  timestamp: string,
  rawBody: Buffer,
  signatureHeader: string
): boolean {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret).update(`${timestamp}.`).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader.trim());
  if (a.length !== b.length) return false;
  return crypto.timingSafeEqual(a, b);
}

پس از تأیید امضا: با کلید API شریک، مثلاً
GET https://api.codal724.ir/api/v1/external/codal/data?table_name=income_statement&updated_at_start=<last_updated_at>
(یا معادل صندوق‌ها / گزارش‌ها) — آن درخواست pull هزینه‌دار است.


متغیرهای محیط (backend)

VariableDefaultRole
EXTERNAL_API_WEBHOOK_MAX_PER_USER3Max enabled endpoints
EXTERNAL_API_WEBHOOK_TIMEOUT_SECONDS10Outbound POST timeout
EXTERNAL_API_WEBHOOK_MAX_RETRIES8Delivery retries
EXTERNAL_API_WEBHOOK_DISABLE_AFTER_FAILURES20Auto-disable endpoint