Vérifier des citations par programmation. Un seul endpoint, en flux SSE.
Base URL
https://api.citetrue.comDémarrage rapide
- 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. - Incluez la clé dans
Authorization: Bearer sk_…à chaque requête. - POSTez un task à
/verify/v2. La réponse est untext/event-stream; consommez les événements SSE jusqu'à voirtask_completed.
Appel minimal :
curl -N -X POST https://api.citetrue.com/verify/v2 \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"[1] Vaswani, A., Shazeer, N., Parmar (2017). Attention is all you need."}'-N désactive la bufferisation curl pour streamer les événements SSE ligne par ligne. Plus besoin de choisir depth : chaque référence suit le même flux. La plupart coûtent 1 crédit ; les références délicates, qui demandent plus de sources de données et plus d'analyse, jusqu'à 5.
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({ 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
429et un en-têteRetry-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.
| Header | Requis | Valeur |
|---|---|---|
| Authorization | yes | Bearer sk_… |
| Content-Type | yes | application/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. Supply exactly one of text (new task) or taskHash (resume). Every reference goes through the same flow — there is no verification level to choose.
Corps de requête
| Champ | Type | Notes |
|---|---|---|
| text | string | New verify task. Max 10MB. Accepts numbered, bulleted, blank-line-separated, BibTeX, or in-text prose with (Author, Year) citations. |
| taskHash | string | Resume an existing task — replays cached state or attaches to live stream. References already charged aren't charged again; any that still need work are finished and billed as usual. |
| force | bool | Bypass the task-level dedup cache (forces a fresh run, billed like a new check). |
| locale | string | Optional 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. |
Idempotence: same text + same user returns the cached task on second POST (no re-billing) unless force: true.
Deprecated fields
depth— still accepted but ignored (1,5,20or omitted all behave the same). Don't send it.refHash+parentTaskHash— legacy single-reference mode kept for older clients. It ignoresdepthand simply finishes that one reference, billed under the normal rules. New integrations shouldn't use it.
Requête exemple (text)
{
"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 (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_completedPer-ref assessment
Each ref_completed event carries an assessment string from this closed set:
authentic— paper exists and is the one cited.valuecontains the matched paper.unsure— found something but can't confirm;noticesandconfidencedescribe 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.cost is the total credits this task has charged for the reference (0–5): 1 for most references, up to 5 for tricky ones that needed more data sources and more analysis, 0 if it was already paid for in another task. It covers every connection and resume of the same task, and the same number is sent on every push, replays included — overwrite it, don't add it up across reconnects. data.depth is kept only for compatibility with older clients — ignore it.
É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; carriescost(credits newly charged during this connection, 0 for a pure replay) and the accountbalanceafterwards (can be negative — see Credits & billing).task_progress— periodic progress %.warn— non-fatal warning.error— terminal task-level failure.
GET /credits
GET /credits/v1 — returns current credit balance. Auth required. The balance can be negative (see Credits & billing).
Crédits et facturation
Most references cost 1 credit. Tricky ones that need more data sources and more analysis can cost up to 5. Each reference is charged 1 credit when it's queued; anything extra is added when it finishes. Cached tasks (same text + user) do not re-bill.
Reading the charge: data.cost in ref_completed is the running total this task has charged for that reference — the same number is sent again on reconnects and replays, so overwrite it rather than adding it up. cost in task_completed is what this connection newly charged (0 for a pure replay), so after a reconnect it won't equal the sum of the per-ref costs. balance is the account balance afterwards.
Running out: a reference that hasn't started when the balance can't cover it comes back as exceeded, and the task still ends with task_completed. If you run out of credits mid-check, references already in progress still finish; the overage is deducted at your next credit reset, so balance can be negative.
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.
Maintenu par l'équipe CiteTrue · Dernière mise à jour: