فرمیت

راهنمای API و وب‌هوک

پاسخ‌های فرم‌هایتان را به CRM، سیستم حسابداری یا هر برنامه دیگری وصل کنید.

دو راه اتصال

ساخت کلید API

از تنظیمات حساب ← کلیدهای API یک کلید بسازید. کلید فقط یک بار نمایش داده می‌شود و با fk_ شروع می‌شود. آن را مثل رمز عبور نگه دارید و هرگز در کد سمت مرورگر قرار ندهید. هر کلید به فرم‌های خودتان و فرم‌هایی که با شما به اشتراک گذاشته شده دسترسی فقط‌خواندنی دارد.

کلید را در هدر Authorization بفرستید:

Authorization: Bearer fk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

سقف درخواست: ۱۲۰ درخواست در دقیقه برای هر کلید. پس از آن پاسخ 429 با هدر Retry-After برمی‌گردد.

فهرست فرم‌ها

GET https://formit.ir/api/v1/forms
{
  "data": [
    { "id": "8f1c…", "title": "ثبت‌نام همایش", "slug": "k3m9x2ab",
      "published": true, "responses": 214,
      "createdAt": "2026-09-01T08:12:00.000Z", "updatedAt": "…" }
  ]
}

پاسخ‌های یک فرم

GET https://formit.ir/api/v1/forms/{formId}/responses?limit=50&since=2026-09-01T00:00:00Z
پارامترتوضیح
limitتعداد در هر صفحه، ۱ تا ۱۰۰ (پیش‌فرض ۵۰)
cursorمقدار nextCursor از پاسخ قبلی، برای صفحه بعد
sinceفقط پاسخ‌های ثبت‌شده از این زمان به بعد (ISO 8601)
{
  "form": {
    "id": "8f1c…", "title": "ثبت‌نام همایش",
    "fields": [ { "id": "name", "type": "text", "label": "نام و نام خانوادگی" }, … ]
  },
  "data": [
    {
      "id": "bd7e412a-…", "createdAt": "2026-09-14T10:03:11.000Z",
      "status": "PAID", "score": null, "amount": 0, "paymentRefId": null,
      "utmSource": "instagram", "utmMedium": null, "utmCampaign": null,
      "answers": {
        "name": "علی رضایی",
        "resume": [ { "name": "cv.pdf", "size": 182044, "url": "https://…signed…" } ]
      }
    }
  ],
  "nextCursor": "a91f…"
}

کلیدهای answers شناسه سوال‌ها هستند؛ عنوان هر سوال را از form.fields بخوانید. لینک فایل‌های آپلودشده امضاشده است و پس از ۷ روز منقضی می‌شود؛ اگر فایل را لازم دارید، همان موقع دانلود و ذخیره کنید. پاسخ‌ها از جدید به قدیم مرتب‌اند؛ تا وقتی nextCursor خالی نشده صفحه بعد را بخوانید.

نمونه با curl

curl -H "Authorization: Bearer $FORMIT_KEY" \
  "https://formit.ir/api/v1/forms/FORM_ID/responses?limit=100"

خطاها

وب‌هوک

در فرم‌ساز، بخش «تنظیمات ← اتصال‌ها» آدرس https سرور خود را وارد کنید. با هر پاسخ جدید یک درخواست POST با بدنه JSON ارسال می‌شود. اگر سرور شما پاسخ 2xx ندهد، تا دو بار دیگر (پس از ۵ و ۳۰ ثانیه) تلاش می‌شود و نتیجه هر ارسال در همان بخش قابل مشاهده است.

رویدادها:

POST /your-endpoint
content-type: application/json; charset=utf-8
x-formit-event: response.submitted
x-formit-delivery: 5b0e…
x-formit-timestamp: 1789203791
x-formit-signature: sha256=3f9a…

{
  "event": "response.submitted",
  "deliveryId": "5b0e…",
  "form": { "id": "8f1c…", "slug": "k3m9x2ab", "title": "ثبت‌نام همایش" },
  "response": { "id": "bd7e…", "status": "PAID", "createdAt": "…", "answers": { … } }
}

بررسی امضا

هر فرم یک کلید امضای اختصاصی دارد که در همان بخش اتصال‌ها نمایش داده می‌شود. امضا برابر است با HMAC-SHA256 روی رشته {timestamp}.{body}. قبل از استفاده از داده، امضا را بررسی کنید و درخواست‌های با زمان قدیمی‌تر از ۵ دقیقه را رد کنید. با x-formit-delivery هم از پردازش دوباره یک ارسال جلوگیری کنید.

// Node.js (Express): use the raw body, not the parsed JSON
const crypto = require("crypto");

function verify(rawBody, headers, secret) {
  const ts = headers["x-formit-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = "sha256=" + crypto.createHmac("sha256", secret)
    .update(ts + "." + rawBody).digest("hex");
  const got = String(headers["x-formit-signature"] || "");
  return got.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
}
<?php // PHP
$raw = file_get_contents('php://input');
$ts  = $_SERVER['HTTP_X_FORMIT_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_FORMIT_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, $secret);
if (abs(time() - (int)$ts) > 300 || !hash_equals($expected, $sig)) {
  http_response_code(401); exit;
}

سوالی دارید؟ با پشتیبانی در تماس باشید.