Zitate programmatisch verifizieren. Ein Endpoint, gestreamt über SSE.
Base URL
https://api.citetrue.comQuickstart
- Zu Dashboard → API-Schlüssel, auf Neuer API-Schlüssel klicken. Den Schlüssel mit Präfix
sk_kopieren — er wird nur einmal angezeigt. - Bei jedem Request den Schlüssel im
Authorization: Bearer sk_…mitsenden. - Einen Task an
/verify/v2POSTen. Die Response ist eintext/event-stream; SSE-Events konsumieren, bistask_completederscheint.
Minimaler Aufruf:
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 deaktiviert curl-Buffering, damit SSE-Events zeilenweise streamen. depth muss nicht mehr gesetzt werden — jede Referenz durchläuft denselben Ablauf. Die meisten kosten 1 Credit; knifflige, die mehr Datenquellen und mehr Analyse brauchen, bis zu 5.
Client-Beispiele
SSE ist eine lang laufende HTTP-Response, bei der jedes Event mit einer Leerzeile (\n\n) endet. Zeilen, die nicht mit data: beginnen, überspringen; den Rest per JSON parsen.
Browser-Hinweis: Das eingebaute EventSource kann keinen Authorization-Header senden — verwenden Sie fetch + ReadableStream wie unten gezeigt.
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)Authentifizierung
API-Schlüssel sind langlebige Bearer-Token der Form sk_<40-char-token>. Im Authorization-Header senden:
Authorization: Bearer sk_AbCd123…- Schlüssel im Dashboard widerrufen — innerhalb weniger Sekunden wirksam.
- Ein Schlüssel kann alles, was der Besitzer kann. Wie ein Passwort behandeln — pro Integration rotieren und scopen.
Rate-Limits
Jeder API-Key erhält einen Token-Bucket-Limiter:
- Burst: 10 Requests.
- Dauerhaft: 60 Requests / Minute (Bucket füllt mit 1 Token/s nach).
- Bei Überschreitung schlägt der Request mit
429undRetry-After-Header (Sekunden) fehl.
Das Limit gilt pro Key; unterschiedliche Keys des gleichen Accounts haben unabhängige Buckets. Credits gelten zusätzlich.
Request-Header
Every endpoint accepts the same authentication and content-type headers; only the request body and URL differ.
| Header | Pflicht | Wert |
|---|---|---|
| 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.
Request-Body
| Feld | Typ | Hinweise |
|---|---|---|
| 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. |
Idempotenz: 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.
Beispiel-Request (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."
}Beispiel-Request (resume)
{
"taskHash": "f0e1d2c3b4a5..."
}Typische Event-Abfolge
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.
SSE-Events
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).
Credits & Abrechnung
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.
Fehlerreferenz
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.
Versionierung & Stabilität
Path-versioned (/verify/v2 etc.). Breaking changes bump the version segment; backwards-compatible additions ship in-place.
Gepflegt vom CiteTrue-Team · Zuletzt aktualisiert: