Verifique citas de forma programática. Un solo endpoint, transmitido por SSE.

Base URL

https://api.citetrue.com

Inicio rápido

  1. Vaya a Panel → Claves API y haga clic en Nueva clave API. Copie la clave que empieza por sk_. Se muestra solo una vez.
  2. Incluya la clave en Authorization: Bearer sk_… en cada petición.
  3. Haga POST de un task a /verify/v2. La respuesta es text/event-stream; consuma eventos SSE hasta ver task_completed.

Llamada mínima:

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 desactiva el buffering de curl para transmitir eventos SSE línea por línea. Ya no hay que elegir depth: todas las referencias pasan por el mismo flujo. La mayoría cuestan 1 crédito; las complicadas, que necesitan más fuentes de datos y más análisis, hasta 5.

Ejemplos de cliente

SSE es una respuesta HTTP persistente donde cada evento termina con una línea en blanco (\n\n). Omita las líneas que no comiencen por data: y haga JSON-parse del resto.

Nota del navegador: EventSource no puede enviar un encabezado Authorization — use fetch + ReadableStream como se muestra abajo.

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)

Autenticación

Las claves API son tokens bearer de larga duración con la forma sk_<40-char-token>. Envíelas en el encabezado Authorization:

Authorization: Bearer sk_AbCd123…
  • Revoque una clave desde el Panel. La revocación surte efecto en segundos.
  • Una clave puede hacer todo lo que el usuario propietario. Trátela como una contraseña — rote y limite el alcance por integración.

Límites de velocidad

Cada clave API tiene un limitador token-bucket:

  • Ráfaga: 10 peticiones.
  • Sostenido: 60 peticiones/minuto (bucket se recarga a 1 token/s).
  • Al excederse, la petición falla con 429 y un encabezado Retry-After (segundos).

El límite se aplica por clave; claves distintas de la misma cuenta tienen buckets independientes. Los créditos se aplican aparte.

Encabezados de petición

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

HeaderRequeridoValor
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. Supply exactly one of text (new task) or taskHash (resume). Every reference goes through the same flow — there is no verification level to choose.

Cuerpo de petición

CampoTipoNotas
textstringNew verify task. Max 10MB. Accepts numbered, bulleted, blank-line-separated, BibTeX, or in-text prose with (Author, Year) citations.
taskHashstringResume 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.
forceboolBypass the task-level dedup cache (forces a fresh run, billed like a new check).
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.

Idempotencia: 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, 20 or omitted all behave the same). Don't send it.
  • refHash + parentTaskHash — legacy single-reference mode kept for older clients. It ignores depth and simply finishes that one reference, billed under the normal rules. New integrations shouldn't use it.

Petición de ejemplo (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."
}

Petición de ejemplo (resume)

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

Secuencia típica de eventos

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

Eventos 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 cost (credits newly charged during this connection, 0 for a pure replay) and the account balance afterwards (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éditos y facturación

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.

Referencia de errores

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.

Versionado y estabilidad

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

Mantenido por el equipo de CiteTrue · Última actualización: