المطورون

Formalini API

قراءة المستندات وحقولها المستخرجة، وإرسال المستندات من أنظمتك، وتصحيح القيم، واستلام إشعارات webhook موثقة عند حدوث أي تغيير. جميع الأمثلة أدناه موضحة بلغات curl وJavaScript وPython وPHP وC#.

عنوان URL الأساسي

تندرج جميع نقاط النهاية تحت عنوان URL الأساسي هذا. الإرسال والاستلام بصيغة JSON.

https://api.formalini.com/api/public/v1

العنوان المختصر api.formalini.com متاح ونشط، وهو العنوان الموضح أعلاه.

المصادقة

أنشئ مفتاح API في التطبيق ضمن قسم عمليات الربط (Integrations)، ثم أرسله كرمز bearer token مع كل طلب. يرتبط كل مفتاح بمساحة عمل واحدة ولا يمكنه الوصول إلا لبياناتها فقط.

  • documents.read — قراءة المستندات وحقولها
  • documents.write — إنشاء المستندات وتصحيح الحقول
  • workflows.run — إرسال الأحداث إلى نقاط webhook لديك عند الطلب

يخضع كل مفتاح لحد أقصى من الطلبات في الدقيقة (60 افتراضياً). تتضمن الاستجابات ترويستي X-RateLimit-Limit وX-RateLimit-Remaining؛ وعند تجاوز الحد ستتلقى رمز الحالة 429 مع Retry-After.

عرض قائمة المستندات

GET /documents?limit=25&status=approved — documents.read

مرتبة من الأحدث إلى الأقدم. تقبل المعلمة limit من 1 إلى 100 (25 افتراضياً)، وتتم تصفية status حسب: queued أو processing أو review أو approved أو exported أو failed.

curl -X GET "https://api.formalini.com/api/public/v1/documents?limit=25&status=approved" \
  -H "Authorization: Bearer pf_live_your_key"
{
  "documents": [
    {
      "id": "b0f1c8d2-5a71-4c0e-9f2a-1d4b6e8c3a90",
      "name": "Job sheet 4821.jpg",
      "status": "approved",
      "average_confidence": 0.94,
      "source": "upload",
      "created_at": "2026-09-11T09:12:04.000Z",
      "fields": [
        { "name": "engineer", "value": "M. Byrne", "type": "text",
          "confidence": 0.97, "page": 1, "valid": true }
      ]
    }
  ]
}

تحل القيم المصححة محل القراءة الأصلية، لذا فإن value هي دائماً القيمة المعتمدة للاستخدام.

جلب مستند واحد

GET /documents/{id} — documents.read

إرجاع المستند متضمناً فئته والمورّد والمبلغ والتاريخ وكافة الحقول.

curl -X GET "https://api.formalini.com/api/public/v1/documents/b0f1c8d2-5a71-4c0e-9f2a-1d4b6e8c3a90" \
  -H "Authorization: Bearer pf_live_your_key"

رفع ملف واستخراج بياناته

POST /documents/upload — documents.write

أرسل صورة الصفحة واستلم البيانات المنظمة مباشرة في الاستجابة نفسها. يظهر المستند في صندوق وارد مساحة العمل مثل أي مستند ممسوح ضوئياً، ويستهلك رصيد ذكاء اصطناعي واحداً لكل صفحة، ويرسل إشعارات webhook فور اكتماله.

  • file — صورة الصفحة؛ كرر الحقل لكل صفحة (حتى 25 صفحة) في المستندات متعددة الصفحات
  • name — اسم اختياري للمستند؛ يُعتمد اسم الملف تلقائياً عند تركه فارغاً
  • template_id — معرّف قالب (template id) اختياري، لإرجاع الحقول بالمسميات المعرفة لديك
  • async — عيّنه كـ true لتلقي الاستجابة 202 فوراً والاستعلام الدوري عبر GET /documents/{id} لجلب النتيجة
curl -X POST "https://api.formalini.com/api/public/v1/documents/upload" \
  -H "Authorization: Bearer pf_live_your_key" \
  -F "file=@invoice-page-1.jpg" \
  -F "file=@invoice-page-2.jpg" \
  -F "name=Invoice 2026-0041"
{
  "document": {
    "id": "8c2a1f76-4d33-4a1e-8f10-72b9e5c4a118",
    "name": "Invoice 2026-0041",
    "status": "review",
    "average_confidence": 0.93,
    "vendor": "Northbridge Supplies",
    "amount": 1249.5,
    "currency": "EUR",
    "document_date": "2026-09-14",
    "pages": 2,
    "credits_spent": 2,
    "fields": [
      { "name": "invoice_number", "value": "2026-0041", "type": "string",
        "confidence": 0.98, "page": 1, "valid": true }
    ]
  }
}

تُقبل صيغ JPEG وPNG وWebP وHEIC، بحجم يصل إلى 100 ميغابايت لكل صفحة. تستغرق قراءة الصفحة بضع ثوانٍ، لذا يرجى ضبط مهلة كافية أو تعيين async=true. يشير الرمز 402 إلى نفاد الرصيد أو السعة التخزينية أو الحد اليومي لمساحة العمل، مع تحديد السبب في الاستجابة.

ملفات PDF غير مدعومة عبر هذه النقطة حالياً: حوّل كل صفحة إلى JPEG أو PNG وأرسلها كحقول ملفات متكررة. يظل رفع ملفات PDF متاحاً عبر التطبيق، حيث تتم معالجة الصفحات محلياً في متصفحك.

إنشاء مستند

POST /documents — documents.write

إرسال مستند تتوفر بياناته لديك مسبقاً. الحقل name إلزامي؛ والحقل fields اختياري ويستوعب حتى 400 إدخال. ينتقل المستند المتضمن لحقول إلى حالة review، بينما ينتقل غير المتضمن لحقول إلى قائمة الانتظار.

curl -X POST "https://api.formalini.com/api/public/v1/documents" \
  -H "Authorization: Bearer pf_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Invoice 2026-0041.pdf",
    "category": "invoice",
    "vendor": "Northbridge Supplies",
    "amount": 1249.5,
    "document_date": "2026-09-14",
    "fields": [
      {
        "name": "invoice_number",
        "value": "2026-0041",
        "type": "text",
        "confidence": 0.99,
        "page": 1
      },
      {
        "name": "total",
        "value": "1249.50",
        "type": "number",
        "confidence": 0.96,
        "page": 1
      }
    ]
  }'
{
  "document": {
    "id": "8c2a…",
    "name": "Invoice 2026-0041.pdf",
    "status": "review",
    "created_at": "2026-09-18T10:02:11.000Z",
    "fields": 2
  }
}

تحديث مستند

PATCH /documents/{id} — documents.write

تغيير الحالة أو تصحيح قيم الحقول بالاسم. يؤدي تعيين الحالة إلى approved أو exported أو review إلى إطلاق إشعار webhook المطابق أيضاً.

curl -X PATCH "https://api.formalini.com/api/public/v1/documents/b0f1c8d2-5a71-4c0e-9f2a-1d4b6e8c3a90" \
  -H "Authorization: Bearer pf_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "approved",
    "fields": [
      {
        "name": "total",
        "value": "1249.50"
      }
    ]
  }'
{ "ok": true, "updated_fields": 1 }

تشغيل إشعارات webhook

POST /workflows/dispatch — workflows.run

إرسال حدث إلى كل webhook نشط ومشترك فيه، لبدء إجراء في نظام آخر عند الطلب. الأحداث المسموح بها: document.processed وdocument.needs_review وdocument.approved وdocument.exported.

curl -X POST "https://api.formalini.com/api/public/v1/workflows/dispatch" \
  -H "Authorization: Bearer pf_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "document.approved",
    "document_id": "b0f1c8d2-5a71-4c0e-9f2a-1d4b6e8c3a90",
    "payload": {
      "target": "erp"
    }
  }'
{ "ok": true, "event": "document.approved", "document_id": "b0f1…" }

نقاط Webhook

أضف عنوان URL للـ webhook في التطبيق وحدد الأحداث المطلوبة. يُرسل كل إشعار عبر طلب POST يحتوي على نص JSON وترويسة توقيع مشفرة باستخدام مفتاح webhook السري الخاص بك.

POST https://your-app.example.com/hooks/formalini
Content-Type: application/json
X-Paperflow-Signature: sha256=<hex hmac of the raw body>

{ "event": "document.processed", "document_id": "b0f1…", "payload": { … } }

تتم إعادة محاولة الإرسال الفاشلة حتى خمس مرات بفترات تأخير متزايدة، مع إمكانية إعادة إرسال أي عملية يدوياً من التطبيق.

تحقق من صحة التوقيع بمطابقته مع نص الطلب الأصلي (raw request body) قبل اعتماد الإشعار:

// Node.js
import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const got = (header || "").replace(/^sha256=/, "");
  return got.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
}

# Python
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, (header or "").removeprefix("sha256="))

// PHP
$expected = hash_hmac('sha256', $rawBody, $secret);
$got = str_replace('sha256=', '', $_SERVER['HTTP_X_PAPERFLOW_SIGNATURE'] ?? '');
$ok = hash_equals($expected, $got);

// C#
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var expected = Convert.ToHexString(hmac.ComputeHash(rawBodyBytes)).ToLowerInvariant();
var ok = CryptographicOperations.FixedTimeEquals(
    Encoding.UTF8.GetBytes(expected),
    Encoding.UTF8.GetBytes(header.Replace("sha256=", "")));

الأخطاء

  • 400 — نص الطلب ليس بصيغة JSON، أو توجد قيمة مطلوبة مفقودة أو غير صالحة
  • 401 — المفتاح غير موجود، أو تم إلغاؤه، أو منتهي الصلاحية
  • 403 — لا يملك المفتاح الصلاحية اللازمة للوصول لنقطة النهاية هذه
  • 404 — لا يوجد مستند بهذا المعرّف في مساحة العمل هذه
  • 429 — تم الوصول إلى الحد الأقصى للطلبات في الدقيقة — يرجى الانتظار ثم إعادة المحاولة
  • 500 — حدث خطأ في النظام؛ توضح الاستجابة تفاصيل الخطأ