تحقق من الاستشهادات برمجيًا. نقطة نهاية واحدة، تدفق عبر SSE.

Base URL

https://api.citetrue.com

بداية سريعة

  1. انتقل إلى لوحة التحكم → مفاتيح API وانقر مفتاح API جديد. انسخ المفتاح الذي يبدأ بـ sk_. يُعرض مرة واحدة فقط.
  2. أضف المفتاح في Authorization: Bearer sk_… مع كل طلب.
  3. أرسل POST لـ task إلى /verify/v2. الاستجابة text/event-stream؛ استهلك أحداث SSE حتى ترى task_completed.

أدنى نداء deep-verify:

curl -N -X POST https://api.citetrue.com/verify/v2 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"depth":5,"text":"[1] Vaswani, A., Shazeer, N., Parmar (2017). Attention is all you need."}'

-N يعطّل تخزين curl المؤقت فتتدفق أحداث SSE سطرًا سطرًا. "depth": 5 يُشغّل كل job عبر خط أنابيب deep الكامل (قواعد بيانات أوسع + أقوى ذكاء اصطناعي)؛ استخدم "depth": 1 لفحص سريع أرخص.

أمثلة العميل

SSE استجابة HTTP طويلة الأمد حيث ينتهي كل حدث بسطر فارغ (\n\n). تجاوز الأسطر التي لا تبدأ بـ data: وقم بتحليل JSON لبقية.

ملاحظة المتصفح: لا يستطيع EventSource المدمج إرسال رأس Authorization — استخدم fetch + ReadableStream كما يظهر أدناه.

Node 18+ with native fetch.

const API = 'https://api.citetrue.com'
const KEY = process.env.API_KEY

async function verify(text) {
  const resp = await fetch(`${API}/verify/v2`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ depth: 5, text }),
  })
  if (!resp.ok) throw new Error(`${resp.status}: ${await resp.text()}`)

  const reader = resp.body.getReader()
  const decoder = new TextDecoder()
  const refs = []
  let buf = ''

  while (true) {
    const { value, done } = await reader.read()
    if (done) break
    buf += decoder.decode(value, { stream: true })
    let idx
    while ((idx = buf.indexOf('\n\n')) !== -1) {
      const chunk = buf.slice(0, idx); buf = buf.slice(idx + 2)
      for (const line of chunk.split('\n')) {
        if (!line.startsWith('data: ')) continue
        const evt = JSON.parse(line.slice(6))
        if (evt.event === 'ref_completed') {
          refs.push(evt.data.ref)
        }
        if (evt.event === 'task_completed') return { refs, balance: evt.data.balance }
        if (evt.event === 'error') throw new Error(evt.error)
      }
    }
  }
}

const out = await verify('[1] Vaswani, A., Shazeer, N., Parmar (2017). Attention is all you need.')
console.log(out)

المصادقة

مفاتيح API رموز bearer طويلة الأمد بالشكل sk_<40-char-token>. أرسلها في ترويسة Authorization:

Authorization: Bearer sk_AbCd123…
  • يمكنك إلغاء مفتاح من لوحة التحكم. الإلغاء ساري خلال ثوانٍ.
  • يمكن للمفتاح فعل كل ما يفعله مستخدمه. تعامل معه ككلمة مرور — دوّره وحدّد نطاقه لكل تكامل.

حدود المعدل

لكل مفتاح API مُحدِّد token-bucket:

  • دفعة: 10 طلبات.
  • مستدام: 60 طلبًا/دقيقة (bucket يُعاد ملؤه بمعدل 1 token/s).
  • عند التجاوز يفشل الطلب بـ 429 مع ترويسة Retry-After (ثوانٍ).

المُحدِّد لكل مفتاح؛ المفاتيح المختلفة لنفس الحساب لها دِلاء مستقلة. الأرصدة تُطبَّق إضافةً لذلك.

ترويسات الطلب

Every endpoint accepts the same authentication and content-type headers; only the request body and URL differ.

Headerمطلوبالقيمة
AuthorizationyesBearer sk_…
Content-Typeyesapplication/json

Responses are 200 OK with Content-Type: text/event-stream.

data: {"event":"<name>","data":{...},"error":""}

POST /verify/v2

Split a text blob into references and verify each. Same endpoint covers three modes — supply exactly one of text, refHash, or taskHash.

جسم الطلب

الحقلالنوعملاحظات
textstringNew verify task. Max 10MB. Accepts numbered, bulleted, blank-line-separated, BibTeX, or in-text prose with (Author, Year) citations (depth ≥ 5 only).
refHashstringUpgrade a single prior reference to a deeper run. Requires depth ≥ 5 and parentTaskHash.
parentTaskHashstringThe task this reference originally belonged to. Required when using refHash.
taskHashstringResume an existing task — replays cached state or attaches to live stream. No re-billing for already-charged refs.
depthint / string1 (default) / 5 / 20. Selects verification level + cost.
forceboolBypass the task-level dedup cache (forces a fresh run, charges full cost).
localestringOptional 2-letter language code ("zh", "ja", "de", …). When set, AI translates the per-ref note into that language and surfaces it under noteTranslated[locale]. Default "" / "en" = no translation.

المعاملات — depth

  • 1 — fast: handles structured reference lists and inline prose (auto-falls back to AI splitter on hard inputs). 1 credit per reference.
  • 5— deep: AI-driven verification; handles unusual formats and gives a stronger verdict. Each reference first gets a fast pass; if that already finds it authentic, it's billed just 1 credit and deep verification is skipped — otherwise 5 (see Credits & billing below).
  • 20 closed beta, not enabled for public API. Same flow as 5 with a higher-tier model.

Idempotency: same text + same depth + same user returns the cached task on second POST (no re-billing) unless force: true.

طلب مثال (text, depth=1)

{
  "text": "[1] Vaswani, A., Shazeer, N., Parmar (2017). Attention is all you need.\n[2] Piketty, T. (2016). Capital in the twenty-first century. Harvard University Press."
}

طلب مثال (من نص) (depth=5)

{
  "depth": 5,
  "text": "[1] Vaswani, A., Shazeer, N., Parmar (2017). Attention is all you need."
}

طلب مثال (job مفرد) (refHash upgrade)

{
  "depth": 5,
  "refHash": "a1b2c3d4e5f6...",
  "parentTaskHash": "f0e1d2c3b4a5..."
}

طلب مثال (resume)

{
  "taskHash": "f0e1d2c3b4a5..."
}

تسلسل الأحداث النموذجي

task_created → refs_created (N refs) →
  [ref_processing + ref_completed] × N (parallel) +
  task_progress × several →
task_completed

Per-ref assessment

Each ref_completed event carries an assessment string from this closed set:

  • authentic — paper exists and is the one cited. value contains the matched paper.
  • unsure— found something but can't confirm; notices and confidence describe why.
  • inauthentic — definitively not found / fabricated / unrelated.
  • invalid— input wasn't a citation; pipeline refused to search before any datasource hit.
  • error — verification failed on this single ref; sibling refs may still succeed. data.errors[] lists tokens (datasource_unavailable, timeout, rate_limited, parse_failed).
  • exceeded — account ran out of credits before this ref could run.

Notices on a result (year mismatch, author mismatch, …) are orthogonal to assessment — even an authentic verdict can carry notices worth showing. data.depthreports the highest depth that has run on this ref (1 / 5 / 20); clients derive a "deep-verified" flag locally as depth ≥ 5.

أحداث SSE

SSE event names emitted during verification. Listen for task_completed as the terminal success event; error for terminal failure.

  • task_created — task accepted, hash assigned.
  • refs_created — text was split into N refs.
  • split_completed — splitting phase finished.
  • ref_processing / ref_status — per-ref progress signal.
  • ref_completed — per-ref final assessment.
  • task_completed — all refs done; carries balance.
  • task_progress — periodic progress %.
  • warn — non-fatal warning.
  • error — terminal task-level failure.

GET /credits

GET /credits/v1 — returns current credit balance. Auth required.

الأرصدة والفوترة

1 credit per ref for depth=1, 5 credits per ref for depth=5. Cached tasks (same text + depth + user) do not re-bill.

Deep verification billing: at depth=5 each reference first gets a fast verification pass. If that already finds it authentic, it's billed just 1 credit and deep verification is skipped; otherwise it's billed 5. The per-ref cost and task_completed totals are authoritative. A single-ref refHash upgrade always runs the full deep verification (5).

مرجع الأخطاء

Standard HTTP status codes apply (400 invalid, 401 auth missing/invalid, 402 insufficient credits, 429 rate-limited, 5xx upstream). SSE-level failures arrive as a final error event.

الإصدارات والاستقرار

Path-versioned (/verify/v2 etc.). Breaking changes bump the version segment; backwards-compatible additions ship in-place.