Vérifier des citations par programmation. Un seul endpoint, en flux SSE.

Base URL

https://api.citetrue.com

Démarrage rapide

  1. Allez sur Tableau de bord → Clés API et cliquez sur Nouvelle clé API. Copiez la clé commençant par sk_. Elle n'est affichée qu'une fois.
  2. Incluez la clé dans Authorization: Bearer sk_… à chaque requête.
  3. POSTez un task à /verify/v2. La réponse est un text/event-stream ; consommez les événements SSE jusqu'à voir task_completed.

Appel minimal 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 désactive le bufferisation curl pour streamer les événements SSE ligne par ligne. "depth": 5 fait passer chaque job par la pipeline deep complète (DBs plus larges + IA la plus forte) ; passez à "depth": 1 pour une vérification rapide moins coûteuse.

Exemples de client

SSE est une réponse HTTP longue où chaque événement se termine par une ligne vide (\n\n). Ignorez les lignes qui ne commencent pas par data: et JSON-parse le reste.

Note navigateur : EventSource ne peut pas envoyer d'en-tête Authorization — utilisez fetch + ReadableStream comme ci-dessous.

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)

Authentification

Les clés API sont des jetons bearer longue durée de la forme sk_<40-char-token>. Envoyez-les dans l'en-tête Authorization :

Authorization: Bearer sk_AbCd123…
  • Révoquez une clé depuis le tableau de bord. La révocation est effective en quelques secondes.
  • Une clé peut faire tout ce que son propriétaire peut faire. Traitez-la comme un mot de passe — rotez et limitez la portée par intégration.

Limites de débit

Chaque clé API dispose d'un limiteur token-bucket :

  • Rafale : 10 requêtes.
  • Soutenu : 60 requêtes / minute (bucket rechargé à 1 token/s).
  • Dépassé, la requête échoue avec 429 et un en-tête Retry-After (secondes).

Le limiteur fonctionne par clé ; différentes clés du même compte ont des buckets indépendants. Les crédits s'appliquent en plus.

En-têtes de requête

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

HeaderRequisValeur
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.

Corps de requête

ChampTypeNotes
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.

Paramètres — 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.

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

Requête exemple (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."
}

Requête exemple (depuis text) (depth=5)

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

Requête exemple (job unique) (refHash upgrade)

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

Requête exemple (resume)

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

Séquence typique d'événements

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.

Événements 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.

Crédits et facturation

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).

Référence d'erreurs

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.

Versionnage et stabilité

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