Document Intelligence
The Document Intelligence API converts documents to Markdown, summarizes content, extracts structured data, and answers queries using Bunyan's tools. Manage your project, API keys, and model configurations in Bunyan, then call the API from your application.
| Operation | Endpoint | Result |
|---|---|---|
| Parse | POST /parse | Markdown text |
| Summarize | POST /summarize | Summary text |
| Extract | POST /extract | JSON object |
| Agentic | POST /agentic | Answer and source references |
| Job status | GET /jobs/{job_id} | Processing status or completed result |
Base URL and Authentication
All endpoints use this production base URL. Set the following variables to run the examples:
export DI_BASE="https://app.bunyan.ai/rag-agents/api/v1/document-intelligence"
export DI_KEY="YOUR_BUNYAN_API_KEY"Authenticate every request with X-API-Key: YOUR_BUNYAN_API_KEY. Send request bodies as JSON with Content-Type: application/json.
Use a project API key created in Bunyan, with the scopes required for your operation. Your organization's plan must include Document Intelligence. Keep the key in your server environment or secret manager.
Quick Start
This request converts a small HTML file containing <h1>Invoice</h1> to Markdown. It requires the parsing scope and no model configuration:
curl --fail-with-body -sS "$DI_BASE/parse" \
-H "X-API-Key: $DI_KEY" \
-H "Content-Type: application/json" \
-d '{
"file": "PGgxPkludm9pY2U8L2gxPg==",
"filename": "sample.html",
"llm_enhanced": false
}'Response — 200 OK
{
"status": "completed",
"result": "# Invoice",
"metadata": {"processing_time_ms": 320}
}All synchronous operations use this response structure. The contents of result depend on the operation. Response examples are illustrative; generated content and processing times vary.
API Key Scopes and Access
| Operation | Required scopes |
|---|---|
Parse with llm_enhanced: false | parsing |
Parse with llm_enhanced: true (default) | parsing, llm |
| Summarize | summarize, llm |
| Extract | extraction, llm |
| Agentic | agentic, llm |
| Job status | Any one of parsing, summarize, extraction, or agentic |
The key owner must remain a member of the organization and have permission to update the project. These permissions also apply when a queued job starts.
Summarize, Extract, and Agentic require an available Base model configuration in Bunyan. Your personal default takes precedence over the organization default, followed by the system default. An Agentic blueprint can specify its own model.
Files and Shared Options
Send files in the JSON body using these fields:
| Field | Type | Description |
|---|---|---|
file | string | Base64-encoded file contents, without a data-URL prefix or line breaks. |
filename | string | Original filename with a supported extension. Required with file. |
Supported extensions: .pdf, .docx, .html, .htm, .ppt, .pptx, .xls, .xlsx, .csv, and .json.
These optional fields are available on all four processing endpoints:
| Field | Type | Default | Description |
|---|---|---|---|
ocr_enabled | boolean | false | Enable OCR when processing a file. |
llm_enhanced | boolean | true | Enable LLM enhancement when processing a file. Set to false for basic parsing and a lower processing-unit cost. |
async | boolean | false | Return a job ID and process the request asynchronously. |
webhook_url | string | Omitted | Public callback URL for an asynchronous job. See Webhooks. |
Place these fields at the top level of the request. The parsing options affect file input only.
Files larger than 5 MiB automatically run asynchronously, even when async is omitted. File-size limits depend on your plan and apply to the decoded content. See file and processing limits.
Endpoints
Each processing endpoint returns 200 with a completed result, or 202 with a job ID for asynchronous processing.
Parse a Document
POST /parse
Convert a file to Markdown. Both file and filename are required; use the runnable request in Quick Start. See Files and Shared Options for supported formats and parsing settings.
Result: a Markdown string in result.
Summarize Content
POST /summarize
Provide either text or a file with filename.
| Field | Type | Required | Description |
|---|---|---|---|
text | string | For text input | Source content. Do not combine with file. |
summary_length | string | No | short, medium (default), or long. |
curl --fail-with-body -sS "$DI_BASE/summarize" \
-H "X-API-Key: $DI_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "The agreement covers maintenance for 24 months. Support is available on weekdays.",
"summary_length": "short"
}'result field: an object containing summary.
{"summary": "The agreement includes 24 months of maintenance and weekday support."}Summary lengths target 1–2 sentences for short, 4–6 for medium, and 8–12 for long. Short source content can produce fewer sentences.
Extract Structured Data
POST /extract
Provide either text or a file with filename. Use schema to define the JSON fields to extract.
| Field | Type | Required | Description |
|---|---|---|---|
text | string | For text input | Source content. Do not combine with file. |
schema | object | No | JSON Schema describing the expected result. If omitted, Bunyan extracts key fields into a JSON object. |
curl --fail-with-body -sS "$DI_BASE/extract" \
-H "X-API-Key: $DI_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Invoice INV-001. Total: 1250.75 USD.",
"schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
"total": {"type": "number"}
},
"required": ["invoice_number", "total"]
}
}'result field: the extracted JSON object.
{"invoice_number": "INV-001", "total": 1250.75}Schema references must be resolvable local fragments, such as #/$defs/address; remote references are unsupported. Invalid schemas return 400. If the generated result does not satisfy the schema, the operation fails.
Run an Agentic Task
POST /agentic
Run a query using the tools available to you in Bunyan. You can attach a file or submit a query on its own.
| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Nonblank instructions or question. Include inline context here; text is unsupported. |
blueprint_id | UUID string | No | Saved blueprint to apply to this request. It must be accessible to the key owner and belong to the key's organization and project. |
file | string | No | Base64-encoded attachment. Requires filename. |
This example asks about an attached HTML file containing “Warranty: 24 months.”:
curl --fail-with-body -sS "$DI_BASE/agentic" \
-H "X-API-Key: $DI_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "What is the warranty period?",
"file": "PHA+V2FycmFudHk6IDI0IG1vbnRocy48L3A+",
"filename": "warranty.html",
"llm_enhanced": false,
"async": true
}'The request returns a job ID. Retrieve the completed result as described in Asynchronous Jobs.
result field: an object containing answer and a references array.
{
"answer": "The warranty lasts 24 months.",
"references": [
{
"type": "document",
"id": "a0b251e5-117d-40f4-809d-8d89899bf695",
"name": "warranty.html",
"description": null,
"url": null
}
]
}Tool availability depends on your permissions and configuration. A blueprint applies its instructions, language, model, and tool selection; inaccessible or missing blueprints return 404. Responses contain the final answer as JSON and do not stream.
References identify the sources used in the answer. A reference to an attached file identifies a temporary source, not a saved document or download URL.
Asynchronous Jobs
Set async: true for long-running requests. Files larger than 5 MiB also use this mode automatically.
Submission response — 202 Accepted
{
"status": "processing",
"job_id": "job_a1b2c3d4e5",
"expires_at": "2026-10-15T12:30:00Z"
}Retrieve the job using the returned job_id:
curl --fail-with-body -sS "$DI_BASE/jobs/JOB_ID_FROM_RESPONSE" \
-H "X-API-Key: $DI_KEY"Completed summary job — 200 OK
{
"status": "completed",
"result": {"summary": "The agreement provides 24 months of coverage."},
"error": null,
"metadata": {"processing_time_ms": 1200}
}status | Response fields | Next step |
|---|---|---|
processing | result and error are null. | Wait before polling again. |
completed | result contains the operation's result; error is null. | Save the result in your application. |
failed | result is null; error describes the failure. | Inspect the error before resubmitting. |
The job endpoint returns HTTP 200 for all three states. Check status before reading result; there is no nested response envelope inside result.
Any key from the same project can retrieve the job if it has current access and at least one DI scope. Jobs expire 24 hours after creation. Completed results are retained for up to one hour after completion, capped by job expiry. Expired jobs, unavailable results, and jobs outside the key's project return 404. Polling does not extend retention.
Each poll costs 0.1 processing units and counts toward the request-rate limit, including repeated reads of a completed result. Polling does not consume the API-call balance. See usage and limits.
Webhooks
To receive an HTTP POST when an asynchronous job completes or fails, include webhook_url in the processing request:
{
"text": "Warranty is 24 months from purchase.",
"summary_length": "short",
"async": true,
"webhook_url": "https://YOUR_PUBLIC_HOST/webhooks/bunyan"
}Send this body to /summarize. Use a publicly reachable HTTP or HTTPS URL; HTTPS is recommended. Private addresses and localhost are blocked, and redirects are not followed. Synchronous requests do not trigger callbacks.
Completed callback
{
"status": "completed",
"job_id": "job_a1b2c3d4e5",
"result": {"summary": "Warranty is 24 months from purchase."},
"metadata": {"processing_time_ms": 1200}
}A failed callback contains status: "failed" and an error string instead of result. Return a 2xx response promptly. Failed deliveries are retried up to three times with a 30-second retry delay. Handle duplicate deliveries using job_id. You can poll for the result if a callback is not received.
Verify the Signature
Before enabling callbacks, confirm webhook availability and how to obtain the verification secret with Bunyan support. This secret is separate from your API key.
The X-DocIntel-Signature header contains the hex-encoded HMAC-SHA256 of the exact raw request body. Validate it before parsing JSON:
import hashlib
import hmac
def valid_signature(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)Do not reserialize the body for verification. The signature contains no timestamp, so your handler must also prevent duplicate processing.
Errors and Troubleshooting
HTTP errors use this structure:
{
"error": {
"code": "invalid_request",
"message": "filename is required when file is provided.",
"details": null,
"request_id": "8b9c920f-8727-4295-b509-2cd76b66fe38",
"documentation_url": "https://wiki.bunyan.ai/"
}
}| HTTP status | Action |
|---|---|
400 | Check JSON, base64 encoding, required fields, input combinations, and extraction schema. |
401 | Check that the API key and its owner are valid and the key is active and unexpired. |
403 | Check key scopes, organization membership, project permissions, and DI plan availability. |
404 | Check the endpoint, job or blueprint ID, project access, and result retention. |
405 | Use the HTTP method listed for the endpoint. |
413 | Reduce the decoded file size to your plan's limit. |
415 | Use a supported file extension. |
422 | Review the validation details in the error. |
429 | Check whether the request rate, processing units, or API-call allowance is exhausted. Follow 429 guidance. |
500 | Review the error message; check model configuration if indicated. Keep the request ID for support. |
504 | Resubmit with async: true if synchronous processing timed out. This creates a new request. |
Include the Request-Id response header when contacting support.
Usage and Limits
Document Intelligence has separate request-rate limits, processing-unit limits, and an API-call allowance. Processing submissions consume one API call once charging is reached; later validation or processing failures do not refund it. Retries are new calls. Job-status reads do not consume this balance.
See Document Intelligence Limits for plan allowances, processing costs, response headers, file-size limits, and retry guidance.