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:
- Create a key — generate an API key on the dashboard (app.docsfra.com), choosing which modules it's authorized for.
- Upload a document —
POST /v1/documents(orPOST /v1/batchesfor multiple files); theidvalue is returned immediately, processing continues in the background. - Poll the job — check status with
GET /v1/jobs/{id}(queued -> processing -> parsing -> indexing -> completed/failed). - Optional: receive a webhook — instead of (or alongside) polling,
receive a
document.completed/document.failednotification. - Run semantic search — use
GET /v1/searchto perform chunk-level hybrid search across indexed documents. - 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 returns403 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 messageinvalid_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 than403).
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:
| Module | Description | Unit | Default rate |
|---|---|---|---|
extract | Extraction | page | 1.00 |
structure | Structuring (reasoning) | page | 0.50 |
embed | Embedding | 1K tokens | 0.02 |
index | Vector indexing | 1K chunk-months | 0.10 |
search | Hybrid search | query | 0.02 |
ask | RAG question answering | query | 0.20 |
memory | Document Memory (identity card) | document | 0.10 |
entities | Entity Graph | document | 0.15 |
reasoning | Reasoning Graph | document | 0.15 |
layout | Layout Model (bounding boxes) | page | 0.05 |
media-cdn | Media CDN | GB-month | 0.05 |
md-cdn | Markdown CDN | GB-month | 0.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:
| HTTP | code | Meaning |
|---|---|---|
| 400 | invalid_request | Missing/invalid field |
| 401 | unauthorized | Missing, invalid, or revoked key |
| 402 | insufficient_credit | Balance doesn't cover the cost of the operation |
| 403 | service_not_enabled | Key isn't authorized for the called module |
| 404 | not_found | Resource doesn't exist or belongs to another tenant |
| 413 | payload_too_large | File size limit exceeded |
| 422 | unprocessable_file | Unsupported format or corrupted file |
| 429 | rate_limited | Throttle limit exceeded (with Retry-After) |
| 500 | internal_error | Unexpected server error |
| 503 | service_unavailable | Subsystem 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:
| Scope | Coverage | Limit |
|---|---|---|
tenant_upload | POST /v1/documents, /v1/batches | 60 / minute |
tenant_status | GET /v1/jobs/{id}, /v1/batches/{id} | 600 / minute |
tenant_search | GET /v1/search | 300 / minute |
tenant_ask | POST /v1/ask | 60 / minute |
test_key_hard_cap | dip_test_ key, all endpoints | 1000 / 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.
| Mode | Key | Model | Billing |
|---|---|---|---|
| Default | Docsfra | Docsfra defaults | flat artifact rates (unchanged) |
| Custom model | Docsfra | your choice | flat rates + model-usage: billed per token at the listed model rates, converted to credits |
| BYOK | yours | your choice | flat 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.