Skip to content

REST API

bibr serve runs a LitServe application exposing the bibr extraction pipeline over HTTP. See Production deployment for running the server (Docker, concurrency, hardware sizing); this page documents the REST surface — endpoints, request/response shapes, caching, and error codes.

The server binds to 127.0.0.1:8000 by default. Interactive docs are at /docs (Swagger UI) and /redoc; these and /openapi.json require the same bearer token as extraction when authentication is enabled.

Endpoints

Health

Method Path Description
GET /health Liveness probe -- LitServe's built-in endpoint; returns plain-text ok (status 200)
GET /ready Readiness probe -- checks OCR service, configured classifier artifacts, and Redis when response caching is enabled; 200 when ready, 503 otherwise

The probes are public. With authentication enabled, an anonymous /ready response contains only {"status": "ready"} or {"status": "not_ready"}. A valid bearer token also exposes checks and the deployment build_sha.

Papers

POST /papers/extract

Extract metadata from a scientific paper synchronously. Returns JSON.

Request: multipart/form-data

This is the only public synchronous extraction ingress. The complete multipart body is limited to 51 MiB by default, including boundaries, headers, and form fields; the file bytes within it are limited to 50 MiB (with MCP_ENABLED the body cap grows to fit a 50 MiB file in base64 form — see the MCP guide). At most 1 MiB of the upload remains in API memory before the multipart spool rolls to disk. Exactly one file part is accepted. The eight optional fields below must each appear at most once and are capped at 64 bytes; duplicate/unknown parts or a second file return 400.

Field Type Required Description
file file Yes Paper file (PDF, DOCX, XML/JATS, HTML, or ePub)
start_page int No Start page for PDFs (0-indexed, inclusive)
end_page int No End page for PDFs (0-indexed, inclusive)
include_figures bool No Emit base64-encoded figure images (default: false)
include_regions bool No Emit the extraction.regions layout debug payload (default: false). Contains per-region geometry and recognition content; response size depends on the document.
crossref bool No Run Crossref/resolver reference enrichment for this request (true) or skip it (false). Omit to follow the server's CROSSREF_ENRICH setting, which is off by default. The response cache keys on the effective value.
consolidate fill | replace No Merge accepted Crossref matches into bib before export (fill fills only missing fields, replace also overwrites disagreeing ones). Omit to defer to the server's CROSSREF_CONSOLIDATE setting.
refs ner | llm | llm-chunked | off No Per-request override of the reference-parsing strategy (REF_PARSE_STRATEGY).
ref_seg geom | region | llm | crf No Per-request override of the reference-segmentation strategy (REF_SEG_STRATEGY).

Response: JSON conforming to the bibr v11.0 schema. Top-level keys include: paper_id, schema_version (its presence at the root is how readers dispatch v11 from earlier versions), source (input-artifact identity: file name, content hash, format), metadata (scalar paper-level metadata), author, text, section, url, bib, xref, figure, table, eq, bib_match, metadata_match (enrichment matches for the paper's own identity), funding, affiliation, qualification_provenance (deployment-qualification surface: identity SHAs, per-task protocol hashes, native-validity + fallback outcome, request counts; null when no LLM ran), extraction (all extraction provenance and telemetry: engines, per-run settings, timings, LLM usage, enrichment completeness, identity receipts, diagnostics receipts and warnings; regions is added there when include_regions=true), and validation (output-validation-gate result: error/warning counts and issue list). Figure and table rows retain their legacy primary fields and add ordered parts with physical payload and source provenance.

metadata is scalar-only by design — pipeline telemetry lives under extraction and the input file's identity under source — so R consumers can call as.data.frame(metadata) cleanly.

Within major version 11 the schema is additive-only: new fields may appear in any 11.x release and clients should ignore keys they don't recognize. Dispatch on the presence of the root schema_version key, never on parsing its value — pre-v11 responses have no such key at all. See CHANGELOG.md for the full v11 break and forward-versioning policy.

Example:

curl -X POST http://localhost:8000/papers/extract \
  -F "file=@paper.pdf" \
  -F "include_regions=false" \
  -F "crossref=true"

LitServe's internal POST /_bibr/inference route accepts only the API process's opaque disk descriptor and returns 404 to direct HTTP callers. Only the upload UUID, filename, size, SHA-256, and extraction options cross the worker queue; neither bytes nor a filesystem path do. Worker decode securely reads and verifies the owned file once, then deletes it.

Async jobs

Holding an HTTP connection open for a full extraction (tens of seconds) is fragile behind proxies and load balancers. These routes offer a fire-and-poll alternative instead:

POST /papers/jobs

Accepts the same multipart/form-data fields as /papers/extract. Returns 202 immediately with {"job_id", "status": "queued", "status_url"} and runs the extraction in the background. It persists the upload once and dispatches the same opaque descriptor through LitServe; it does not rebuild or self-proxy a multipart request.

GET /papers/jobs/{id}

Returns the job's status (queued, running, succeeded, or failed) plus timestamps — no result body. A succeeded status includes a result_url pointing at the next endpoint.

GET /papers/jobs/{id}/result

Returns the extracted paper JSON once the job has succeeded (same shape as /papers/extract's response). Responds 409 while the job is still queued/running, or the job's original error and status code if it failed.

Jobs are held in an in-process store and purged after JOBS_TTL_SECONDS (default 3600); JOBS_MAX_ACTIVE (default 32) caps concurrently active jobs, returning 429 past the cap, and JOBS_MAX_RUNNING (default 2) caps how many run at once. Completed results are also evicted oldest-first beyond JOBS_MAX_RETAINED results (default 128) or JOBS_MAX_RETAINED_BYTES of encoded JSON (default 256 MiB; 0 disables the byte budget); the newest result is always kept, so a fetch of /result can answer 404 once a result has been evicted. The whole async API can be disabled with JOBS_ENABLED=false. By default (JOBS_STORE=memory) the job queue, status, and results are process-local and a server restart loses them. JOBS_STORE=redis keeps status and results in Redis instead, so any replica of a load-balanced deployment answers the polls for a job another replica accepted and the active-job cap spans all replicas — see Multiple bibr-serve replicas. Each status carries replica, the instance executing the job; with the Redis store unreachable the job routes answer 503. The service always pins one HTTP API process per instance—even with jobs disabled—because upload ownership and dispatch tracking are process-local. PIPELINE_RESTART_WORKERS=false fail-stops on worker death; true is an unsupported opt-in until the locked LitServe compatibility gate proves reliable completion notification and does not make jobs durable.

Authentication

Set AUTH_API_KEY to require a bearer token on every route except /health and /ready:

curl -X POST http://localhost:8000/papers/extract \
  -H "Authorization: Bearer your-secret-token" \
  -F "file=@paper.pdf"

A missing or wrong token gets a 401 with a WWW-Authenticate: Bearer header. When AUTH_API_KEY is unset, the CLI permits loopback-only serving; network-visible binds require a key at least 32 characters long. See Authentication in the deployment guide for the production-hardening checks (ENVIRONMENT=production) that force it on.

Caching

When CACHE_ENABLED=true (the default) and Redis is configured, the API caches successful extraction responses. Keys distinguish file content, page range, figure/region output, consolidation, and reference-strategy overrides. The cache namespace also includes a settings fingerprint and code version. Identical concurrent cache misses are coalesced; failed Redis operations are bounded and extraction continues without the cache.

Configure caching:

Variable Description Default
CACHE_ENABLED Enable response caching when Redis is configured true
REDIS_URL Redis connection URL auto-generated
REDIS_PASSWORD Redis password (none)
CACHE_VERSION Cache key prefix version auto-computed from source hash
CACHE_TTL_SECONDS Cache TTL 86400 (24h)
CACHE_OPERATION_TIMEOUT_SECONDS Maximum wait for one cache operation 5

Request metering

With METER_ENABLED=true (the default), non-probe HTTP responses carry x-request-id and x-bibr-duration-ms. A valid client-supplied x-request-id is echoed; otherwise the server generates one. Request and extraction records go to the bibr.serve.metering logger; METER_LOG_PATH optionally adds a rotating JSONL file. Cache hits do not count the original extraction's LLM tokens as new usage.

Error responses

Status Meaning
400 Invalid input (missing filename, malformed/bounded option, duplicate or unknown multipart part)
401 Missing or invalid bearer token (AUTH_API_KEY set)
404 Unknown job id (expired past JOBS_TTL_SECONDS, evicted by the retention limits, or never existed)
409 Job result requested before the job finished
413 Upload limit exceeded (50 MiB file / 51 MiB multipart envelope)
422 Extraction processing error
429 Upload admission or async-job active cap reached
500 Unexpected internal error
502 Upstream service failed (OCR server, LLM API)
503 /ready reports an unavailable dependency or required classifier artifact
504 Pipeline processing timed out
503 Job store unreachable (JOBS_STORE=redis): the upload was dropped and nothing queued — retry later
507 Insufficient temporary storage for the disk-backed upload spool