API لسير عمل تم التحقق منه

تحقّق من سير العمل قبل استخدام API

ابدأ في محطة العمل، وتأكد من أن المخرجات التي راجعتها تطابق سير عملك، ثم استخدم API لعمليات الاستخراج المتكررة.

Base: https://pdf2text.ai/api/v1

المصادقة

تتطلب جميع طلبات API رمز Bearer في ترويسة Authorization. أنشئ المفاتيح من إعدادات الحساب بعد التحقق من سير عمل قابل للتكرار.

إدارة مفاتيح API
# Set your API key
export P2T_API_KEY="your_api_key_here"

# Include in all requests
curl -H "Authorization: Bearer $P2T_API_KEY" ...
import requests
import os

API_KEY = os.environ["P2T_API_KEY"]
headers = {"Authorization": f"Bearer {API_KEY}"}
const API_KEY = process.env.P2T_API_KEY;

const headers = {
  'Authorization': `Bearer ${API_KEY}`
};

حدود الاستخدام

تتضمن خطة Firm عدد 1500 صفحة شهريًا لمسارات عمل محطة العمل التي تمت مراجعتها وعمليات الاستخراج عبر API التي تم التحقق منها. تستخدم كل صفحة تتم معالجتها صفحة واحدة من هذا الحد.

يُقاس الاستخدام بالصفحات التي تتم معالجتها، وليس باستدعاءات API. لا يستهلك رفع الملفات أو تنزيل النتائج أو الصادرات أي صفحات، لكن إعادة تشغيل الاستخراج تعيد معالجة تلك الصفحات وتستهلكها مرة أخرى.

صيغ الرفع المدعومة هي PDF وPNG وJPEG وWebP، بحد أقصى 50 MiB لكل ملف. يحدّ النشر الحالي أيضًا حجم طلب multipart الكامل بـ 100 MiB، بما في ذلك جميع الملفات وبيانات النموذج الإضافية. تقتصر عمليات الرفع على 20 ملفًا لكل طلب، و100 ملف لكل مجموعة، و500 صفحة لكل مستند أو عملية تشغيل، و1,000 صفحة مخزنة لكل مجموعة. يمكن أن يصل حجم الصور إلى 20,000 بكسل في أي من البعدين و40 ميغابكسل؛ وتُرفض صفحات PDF التي قد تتجاوز حدود البكسلات هذه عند دقة العرض المستخدمة في OCR.

لا توجد حصة منفصلة لاستدعاءات API. عمليات الاستخراج غير متزامنة وتدخل قائمة انتظار المعالجة، لذا قد يختلف وقت الإكمال حسب حجم المستند وحمل النظام.

حدود الاستخدام العادل الافتراضية هي 30 عملية رفع، و60 بدء تشغيل، و600 عملية قراءة أو تصدير لكل حساب في الساعة. تتضمن الاستجابة 429 الترويسة Retry-After؛ انتظر تلك المدة قبل إعادة المحاولة.

استخدم محطة العمل للتحقق من تخطيطات المستندات وقواعد المراجعة وصيغ التصدير قبل الاعتماد على الأتمتة عبر API.

مقارنة الخطط
POST

رفع المستندات

ارفع ملفًا واحدًا أو أكثر بصيغة PDF أو PNG أو JPEG أو WebP لإنشاء مجموعة مستندات. يتم التحقق من بايتات الملفات وعدد الصفحات وأبعاد الصور قبل حفظ أي شيء. تُرجع عملية الرفع الناجحة الاستجابة 201 Created مع قيمة page_count التي تم التحقق منها لكل مستند.

نقطة النهاية

POST /api/v1/documents/upload/

المعاملات

file / files binary PDF أو PNG أو JPEG أو WebP (مطلوب؛ كرّر files لرفع عدة ملفات)
grouping_id uuid اختياري. أضِف إلى إحدى مجموعات API الحالية لديك. لا يمكن المطالبة بمساحات العمل المجهولة عبر UUID، وتجعل عملية التشغيل النشطة مجموعتها غير قابلة للتعديل حتى اكتمالها.
document_type string اختياري. تلميح التصنيف.
password string اختياري. يفتح ملفات PDF المحمية بكلمة مرور في هذا الطلب. يُستخدم لفتح الملفات فقط ولا يُخزَّن. من دونه يعيد هذا الملف encrypted_pdf، وتعيد كلمة المرور الخاطئة pdf_password_incorrect، وتعيد المحاولات الخاطئة المتكررة للملف نفسه 429.
# Upload a PDF file
curl -X POST https://pdf2text.ai/api/v1/documents/upload/ \
  -H "Authorization: Bearer $P2T_API_KEY" \
  -F "file=@invoice.pdf"

# Add to existing group
curl -X POST https://pdf2text.ai/api/v1/documents/upload/ \
  -H "Authorization: Bearer $P2T_API_KEY" \
  -F "file=@invoice2.pdf" \
  -F "grouping_id=a1b2c3d4-..."
import requests

url = "https://pdf2text.ai/api/v1/documents/upload/"

# Upload single file
with open("invoice.pdf", "rb") as f:
    response = requests.post(
        url,
        headers=headers,
        files={"file": f}
    )

data = response.json()
group_id = data["group_id"]
const { readFile } = require('node:fs/promises');

const form = new FormData();
form.append(
  'file',
  new Blob([await readFile('invoice.pdf')], { type: 'application/pdf' }),
  'invoice.pdf'
);

const response = await fetch(
  'https://pdf2text.ai/api/v1/documents/upload/',
  {
    method: 'POST',
    headers,
    body: form
  }
);
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
const { group_id } = await response.json();
201 Created
{
  "status": "success",
  "group_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "documents": [
    {
      "doc_id": 42,
      "uid": "1847f600-...",
      "grouping_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "original_filename": "invoice.pdf",
      "file_type": "pdf",
      "page_count": 3,
      "status": "pending"
    }
  ]
}

أضف الملفات إلى مجموعة قبل تشغيلها الأول فقط. للفواتير اللاحقة، أنشئ مجموعة جديدة؛ وإلا فإن التشغيل دون تصفية سيعالج كل مستند موجود بالفعل في تلك المجموعة.

POST

بدء عملية الاستخراج

ابدأ المعالجة غير المتزامنة لمجموعة مستندات. استخدم التوجيه التلقائي عندما تريد أن يصنّف PDF2TEXT المستندات قبل الاستخراج.

أرسل الترويسة Idempotency-Key مع كل طلب بدء. يؤدي تكرار المفتاح نفسه مع الجسم نفسه إلى إرجاع عملية التشغيل نفسها؛ وتؤدي إعادة استخدام المفتاح لطلب مختلف إلى إرجاع 409. بعد فشل نهائي، استخدم مفتاحًا جديدًا لإنشاء عملية تشغيل بديلة عن قصد. تُرجع عملية التشغيل الجديدة في قائمة الانتظار الاستجابة 202 Accepted. لا يمكن أن تكون أكثر من عملية تشغيل واحدة نشطة لكل مجموعة في الوقت نفسه، وتحجز عمليات التشغيل النشطة صفحات الحساب التي يمكنها معالجتها.

تؤكد الاستجابة 202 قبول عملية التشغيل، وليس توفر رصيد لكل صفحة مطلوبة. إذا كان رصيد الحساب المشترك أقل مما تتطلبه عملية التشغيل، يعالج API الصفحات المحجوزة وينتهي بحالة partial مع credit_limit_reached=true. تحقّق من الحالة النهائية لعملية التشغيل قبل اعتبار الاستيراد مكتملًا.

يجب أن تستخدم عناوين URL لرد الاستدعاء بروتوكول HTTPS عامًا، ولا يمكنها إعادة التوجيه إلى وجهة أخرى. يتم التسليم بشكل غير متزامن، بمهلة طلب قدرها 10 ثوانٍ، مع ما يصل إلى أربع محاولات إعادة عند أخطاء الاتصال المؤقتة واستجابات HTTP 429 وHTTP 5xx، باستخدام فترات تراجع قدرها 30 ثانية ودقيقتان و10 دقائق.

عند توفير callback_secret، تحقّق من X-PDF2TEXT-Signature بحساب HMAC-SHA256 على جسم الطلب كما هو تمامًا ومقارنته بقيمة sha256=. استخدم X-PDF2TEXT-Run-ID أو X-PDF2TEXT-Idempotency-Key لإزالة التكرار في عمليات التسليم.

The callback JSON body is {"event": "idp.run.completed", "run": {...}}; run uses the same full result shape as GET ?include=results. A signature header is sent only when callback_secret was included in the start request.

نقطة النهاية

POST /api/v1/groups/{group_id}/runs/

جسم الطلب

auto_route boolean تصنيف تلقائي (افتراضي: true)
extraction_mode enum auto أو raw_text أو financial_table أو general_table أو unified. استخدم template_id أو template_slug لمخطط مخصص.
template_id / template_slug uuid / string استخدم واحدًا فقط لفرض قالب محدد
selected_pages array قائمة اختيارية غير فارغة من {docUid, pageNumber}؛ تؤدي الصفحات غير الصالحة إلى رفض الطلب بالكامل
construction_project_id uuid مشروع اختياري مملوك لحساب API
callback_url string عنوان URL للـ Webhook
callback_secret string مفتاح توقيع HMAC
# Start extraction with auto-routing
curl -X POST https://pdf2text.ai/api/v1/groups/$GROUP_ID/runs/ \
  -H "Authorization: Bearer $P2T_API_KEY" \
  -H "Idempotency-Key: invoice-import-123" \
  -H "Content-Type: application/json" \
  -d '{"auto_route": true}'
# Start extraction run
url = f"https://pdf2text.ai/api/v1/groups/{group_id}/runs/"

response = requests.post(
    url,
    headers={**headers, "Idempotency-Key": "invoice-import-123"},
    json={"auto_route": True}
)

run_data = response.json()
run_id = run_data["run_id"]
// Start extraction run
const response = await fetch(
  `https://pdf2text.ai/api/v1/groups/${groupId}/runs/`,
  {
    method: 'POST',
    headers: {
      ...headers,
      'Idempotency-Key': 'invoice-import-123',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ auto_route: true })
  }
);

const { run_id } = await response.json();
202 Accepted
{
  "status": "success",
  "run_id": "b3143b91-...",
  "job_id": "idp-run-b3143b91-...",
  "group_name": "ocr_job_a1b2c3d4...",
  "idempotent_replay": false,
  "run": {
    "id": "b3143b91-...",
    "status": "queued",
    "job_id": "idp-run-b3143b91-...",
    "total_pages": 3,
    "pages_processed": 0
  }
}
GET

جلب النتائج

استقصاء نقطة نهاية التشغيل أو استخدم webhooks لجلب نتائج الاستخراج. صدّر بتنسيق JSON أو Excel.

استجابة عملية التشغيل الافتراضية خفيفة للاستعلام المتكرر ولا يتم تخزينها مؤقتًا أبدًا. اقرأ run.status داخل كائن run المتداخل. الحالات النهائية هي complete وpartial وerror. بعد الوصول إلى حالة نهائية، اطلب include=results مرة واحدة لاسترداد full_text وstructured_output وdocuments.

يتم الإبقاء على credits_remaining للتوافق، ويسجّل الرصيد التاريخي بعد عملية التشغيل تلك. يسمّي credits_remaining_after_run القيمة التاريخية نفسها بشكل صريح، بينما يُبلغ account_credits_remaining عن الرصيد المشترك الحالي للحساب عند إنشاء الاستجابة.

نقاط النهاية

GET /api/v1/runs/{run_id}/ GET /api/v1/runs/{run_id}/?include=results GET /api/v1/runs/{run_id}/export.json GET /api/v1/runs/{run_id}/export.xlsx GET /api/v1/runs/{run_id}/export.xlsx?date_format=MM/DD/YYYY

بالنسبة إلى كشوف الحساب، يحتوي export.xlsx أيضًا على ورقتي CSV لـ QuickBooks وXero. تستخدم تواريخهما تنسيق التاريخ المحفوظ في حسابك، وإلا فترتيب بلد الكشف. مرّر date_format (DD/MM/YYYY أو MM/DD/YYYY أو YYYY/MM/DD أو YYYY-MM-DD) لاختياره؛ وتبقى الأوراق الأخرى بتنسيق YYYY-MM-DD.

رموز حالة الاستجابة

200 401 404
# Lightweight status poll
curl https://pdf2text.ai/api/v1/runs/$RUN_ID/ \
  -H "Authorization: Bearer $P2T_API_KEY"

# Fetch completed results once, then export
curl "https://pdf2text.ai/api/v1/runs/$RUN_ID/?include=results" \
  -H "Authorization: Bearer $P2T_API_KEY"

curl -o results.xlsx \
  https://pdf2text.ai/api/v1/runs/$RUN_ID/export.xlsx \
  -H "Authorization: Bearer $P2T_API_KEY"
import time

run_url = f"https://pdf2text.ai/api/v1/runs/{run_id}/"
terminal = {"complete", "partial", "error"}
delay = 2

# Poll lightweight state with bounded exponential backoff
while True:
    response = requests.get(run_url, headers=headers)
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", delay))
        time.sleep(retry_after)
        delay = min(30, max(10, delay * 2))
        continue
    response.raise_for_status()
    run = response.json()["run"]

    if run["status"] in terminal:
        break

    time.sleep(delay)
    delay = min(30, max(10, delay * 2))

if run["status"] == "error":
    raise RuntimeError(run["error_message"])

results = requests.get(run_url, params={"include": "results"}, headers=headers).json()["run"]

excel = requests.get(
    f"{run_url}export.xlsx",
    headers=headers
)
with open("results.xlsx", "wb") as f:
    f.write(excel.content)
// Poll lightweight state
const pollResults = async (runId) => {
  const runUrl = `https://pdf2text.ai/api/v1/runs/${runId}/`;
  const terminal = new Set(['complete', 'partial', 'error']);
  let delay = 2000;
  while (true) {
    const response = await fetch(runUrl, { headers });
    if (response.status === 429) {
      const retryAfter = Number(response.headers.get('Retry-After') || delay / 1000);
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      delay = Math.min(30000, Math.max(10000, delay * 2));
      continue;
    }
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    const { run } = await response.json();

    if (terminal.has(run.status)) {
      if (run.status === 'error') throw new Error(run.error_message);
      const resultResponse = await fetch(`${runUrl}?include=results`, { headers });
      return (await resultResponse.json()).run;
    }

    await new Promise(r => setTimeout(r, delay));
    delay = Math.min(30000, Math.max(10000, delay * 2));
  }
};

const results = await pollResults(runId);
الاستجابة مع include=results
{
  "status": "success",
  "run": {
    "id": "b3143b91-...",
    "status": "complete",
    "total_pages": 3,
    "pages_processed": 3,
    "credits_remaining_after_run": 497,
    "account_credits_remaining": 497,
    "full_text": "...",
    "structured_output": { /* grouped output */ },
    "documents": [
      {
        "doc_id": 42,
        "document_name": "invoice.pdf",
        "ocr_text": "...",
        "structured_output": { /* document output */ }
      }
    ]
  }
}
GET

القوالب

قائمة قوالب الاستخراج المتاحة. استخدم معرفات القوالب لفرض مخططات استخراج محددة.

نقطة النهاية

GET /api/v1/templates/
إدارة القوالب
# List available templates
curl https://pdf2text.ai/api/v1/templates/ \
  -H "Authorization: Bearer $P2T_API_KEY"
# List available templates
response = requests.get(
    "https://pdf2text.ai/api/v1/templates/",
    headers=headers
)

templates = response.json()["templates"]
for t in templates:
    print(f"{t['name']}: {t['id']}")
// List available templates
const response = await fetch(
  'https://pdf2text.ai/api/v1/templates/',
  { headers }
);

const { templates } = await response.json();
templates.forEach(t => console.log(`${t.name}: ${t.id}`));
الاستجابة
{
  "status": "success",
  "templates": [
    {
      "id": "198aa5be-ea8b-4d67-bdb5-625f5d7d29e8",
      "slug": "invoice",
      "name": "Invoice",
      "description": "Standard invoice extraction",
      "extraction_mode": "financial_table"
    },
    {
      "id": "4317707a-f0da-4c2f-a1ec-d0119d96b55c",
      "slug": "receipt",
      "name": "Receipt",
      "description": "Receipt and expense extraction",
      "extraction_mode": "financial_table"
    }
  ]
}

تحتاج مساعدة؟

استخدم قائمة انتظار المراجعة لفحص الحقول المستخرجة والاحتفاظ بسياق المراجعة.