Docsfra
API Documentation
v1

Getting Started and Auth

Docsfra API is a modular, machine-to-machine (M2M) interface that turns your documents into AI-ready, searchable/queryable data through extraction. This section covers the core concepts you need to know before integrating: API key, Bearer auth, entitlement (module authorization), metering (credits), and error/rate-limit behavior.

What is Docsfra

After a document is uploaded, it's processed server-side module by module:

extract -> structure -> embed -> index

This pipeline runs automatically in the background — you don't need to trigger each stage separately. Once a document is indexed, two query modules come into play: semantic search (search) and question answering/RAG (ask). Each module is billed separately (see Metering and credits) and authorized separately (see Entitlement).

End-to-end flow

A typical integration proceeds in this order:

  1. Create a key — generate an API key on the dashboard (app.docsfra.com), choosing which modules it's authorized for.
  2. Upload a documentPOST /v1/documents (or POST /v1/batches for multiple files); the id value is returned immediately, processing continues in the background.
  3. Poll the job — check status with GET /v1/jobs/{id} (queued -> processing -> parsing -> indexing -> completed/failed).
  4. Optional: receive a webhook — instead of (or alongside) polling, receive a document.completed / document.failed notification.
  5. Run semantic search — use GET /v1/search to perform chunk-level hybrid search across indexed documents.
  6. Ask a question — use POST /v1/ask, the RAG endpoint that combines retrieval and synthesis in a single call.

Each of these steps is covered in detail on its own page: Upload, Polling, Webhook, Semantic Search, Question Answering.

API key

Every request is authenticated with an API key. Keys come in two types:

  • dip_live_... — real tenant data; fully subject to entitlement, metering, and rate limits.
  • dip_test_... — for staging/integration testing; exempt from billing and tenant-based rate limits, instead subject to a fixed, generous hard cap (default 1000 requests/day, per key). Test keys are not exempt from entitlement checks — calling an unauthorized module still returns 403 service_not_enabled.

Keys are created and revoked only from the dashboard (app.docsfra.com, session-based auth) — the API itself does not expose key CRUD operations. When creating a key, you also choose which modules it's authorized for (see Entitlement). When a new key is created, the raw value is shown only in that response and never shown again — store it somewhere secure.

Authenticating with Bearer

All requests must include the key in the Authorization header as a Bearer token:

Authorization: Bearer dip_live_a1b2c3d4e5f6...
  • Missing/invalid key -> 401 unauthorized
  • Revoked key -> also 401 unauthorized, with message invalid_or_revoked_key
  • Once a key is validated, all queries are automatically scoped to that key's tenant. Even if you query a resource belonging to another tenant by id, you'll get 404 (to avoid leaking the resource's existence, rather than 403).

Entitlement: module-based access

Each API key can only access the modules it has been explicitly granted. Module codes: extract | structure | embed | index | search | ask | media-cdn | md-cdn. The list of modules a key is authorized for is selected on the dashboard when the key is created/edited, and is always bounded by the tenant's plan scope — a key cannot be authorized for a module the tenant doesn't have.

If a request calls a module the key isn't authorized for, it returns 403 service_not_enabled:

{
  "error": {
    "code": "service_not_enabled",
    "message": "This API key is not authorized for the 'ask' module",
    "request_id": "req_9f8a7b6c"
  }
}

This check is independent of credit balance — even with a sufficient balance, you cannot call an unauthorized module.

Metering and credits

Every successful module call is deducted from the tenant's credit balance. Every newly registered tenant starts with a 250 credit welcome bonus. If the balance doesn't cover the cost of the requested operation, the request is rejected at pre-check: 402 insufficient_credit.

For dip_test_ keys, calls are still metered (a usage record is created) but not deducted from the balance.

Default (global) catalog rates:

ModuleDescriptionUnitDefault rate
extractExtractionpage1.00
structureStructuring (reasoning)page0.50
embedEmbedding1K tokens0.02
indexVector indexing1K chunk-months0.10
searchHybrid searchquery0.02
askRAG question answeringquery0.20
memoryDocument Memory (identity card)document0.10
entitiesEntity Graphdocument0.15
reasoningReasoning Graphdocument0.15
layoutLayout Model (bounding boxes)page0.05
media-cdnMedia CDNGB-month0.05
md-cdnMarkdown CDNGB-month0.02

These rates can be overridden per tenant; you can always see your current rates on the usage/pricing screen in the dashboard — the table here is only the default reference values.

Note: unlike extract/structure/embed/index/search/ask (charged per call), memory/entities/reasoning/layout are charged once per document (or per page, for layout) at the moment that artifact is produced — reading it back afterwards through its endpoint is free (see Extraction & Artifacts → Pricing).

Error format

All errors are returned in the same envelope:

{ "error": { "code": "...", "message": "...", "request_id": "..." } }

The most common codes you'll encounter:

HTTPcodeMeaning
400invalid_requestMissing/invalid field
401unauthorizedMissing, invalid, or revoked key
402insufficient_creditBalance doesn't cover the cost of the operation
403service_not_enabledKey isn't authorized for the called module
404not_foundResource doesn't exist or belongs to another tenant
413payload_too_largeFile size limit exceeded
422unprocessable_fileUnsupported format or corrupted file
429rate_limitedThrottle limit exceeded (with Retry-After)
500internal_errorUnexpected server error
503service_unavailableSubsystem temporarily unavailable

Rate limit

Rate limits are keyed per tenant (not per IP); dip_test_ keys are instead subject to their own fixed hard cap:

ScopeCoverageLimit
tenant_uploadPOST /v1/documents, /v1/batches60 / minute
tenant_statusGET /v1/jobs/{id}, /v1/batches/{id}600 / minute
tenant_searchGET /v1/search300 / minute
tenant_askPOST /v1/ask60 / minute
test_key_hard_capdip_test_ key, all endpoints1000 / day (per key)

When the limit is exceeded, 429 rate_limited is returned along with a Retry-After header — the number of seconds to wait before retrying:

HTTP/1.1 429 Too Many Requests
Retry-After: 42

It's recommended to honor the Retry-After value and implement exponential backoff on the client side.

Model selection & BYOK

Entirely optional — if you configure nothing, Docsfra defaults apply and nothing changes. Per pipeline lane (structuring, contextual, memory, entity, reasoning, rag) you can pick any model from the OpenRouter catalog, and optionally bring your own provider API key. Configuration lives in the Console under Models.

ModeKeyModelBilling
DefaultDocsfraDocsfra defaultsflat artifact rates (unchanged)
Custom modelDocsfrayour choiceflat rates + model-usage: billed per token at the listed model rates, converted to credits
BYOKyoursyour choiceflat artifact rates only — model costs go to your provider bill

You can also point any lane at your own OpenAI-compatible endpoint (Azure OpenAI, vLLM, Ollama, LiteLLM…): enter the endpoint URL (base URLs get /chat/completions appended automatically) and a free-text model name; the API key is optional for self-hosted engines. Custom endpoints must be reachable from the public internet.

Key security: BYOK keys are stored encrypted at rest, are never logged, and never returned by the API (only a last-4 key_hint). If your key is rejected by the provider, core endpoints (/v1/ask) return a clear error — Docsfra never silently falls back to platform keys. Every processing step records the model used in the document's provenance chain, so model choice is fully auditable.