# Create Agent Source: https://docs.okrapdf.com/api-reference/agents/create-agent POST /v1/agents Create a reusable agent configuration with model, instructions, and optional table binding. ## Overview An agent defines how sessions behave — which model to use, what system instructions to follow, and optionally which table to write extracted data into. Human-readable name for the agent. Model to use for completions. Defaults to `"default"`. System instructions for the agent. Guides how the agent processes documents and uses tools. Bind a typed table to this agent. Sessions created with this agent will have `doc_sql` and `table_sql` tools available for reading documents and writing to the table. JSON Schema for structured output. When set, completions will conform to this schema. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/agents \ -H "Authorization: Bearer okra_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "invoice-extractor", "system": "Extract vendor, amount, and date from each invoice. Insert one row per document.", "table_id": "tbl_abc123" }' ``` ### Response (201) ```json theme={null} { "id": "agent_cf3de29f5a384695", "name": "invoice-extractor", "model": "default", "system": "Extract vendor, amount, and date from each invoice. Insert one row per document.", "table_id": "tbl_abc123", "output_schema": null, "version": 1, "created_at": "2026-04-14T05:30:00Z", "updated_at": "2026-04-14T05:30:00Z" } ``` # Get Agent Source: https://docs.okrapdf.com/api-reference/agents/get-agent GET /v1/agents/{agentId} Retrieve a single agent by ID. ## Overview Returns the full configuration of an agent, including system prompt and table binding. The agent ID (e.g. `agent_cf3de29f5a384695`). ```bash theme={null} curl https://api.okrapdf.com/v1/agents/agent_cf3de29f5a384695 \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "id": "agent_cf3de29f5a384695", "name": "invoice-extractor", "model": "default", "system": "Extract vendor, amount, and date from each invoice.", "table_id": "tbl_abc123", "output_schema": null, "version": 1, "created_at": "2026-04-14T05:30:00Z", "updated_at": "2026-04-14T05:30:00Z" } ``` # List Agents Source: https://docs.okrapdf.com/api-reference/agents/list-agents GET /v1/agents List all agents owned by the authenticated user. ## Overview Returns a paginated list of agents belonging to the authenticated user. Maximum number of agents to return. Default `20`, max `100`. Pagination cursor from a previous response. ```bash theme={null} curl https://api.okrapdf.com/v1/agents \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "data": [ { "id": "agent_cf3de29f5a384695", "name": "invoice-extractor", "model": "default", "table_id": "tbl_abc123", "version": 1, "created_at": "2026-04-14T05:30:00Z" } ], "has_more": false } ``` # Run Collection Agent Source: https://docs.okrapdf.com/api-reference/agents/run-collection-agent POST /v1/collections/{colId}/agents/{agentId}/run Run an agent against a collection. ## Overview Runs a visible built-in or custom agent across a collection. Collection ID. Agent ID. Optional run input payload. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/collections/col-abc123/agents/agent_abc123/run \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "prompt": "Compare revenue across documents" } }' ``` # Run Document Agent Source: https://docs.okrapdf.com/api-reference/agents/run-document-agent POST /v1/documents/{docId}/agents/{agentId}/run Run an agent against a single document. ## Overview Runs a visible built-in or custom agent against one document. Document ID. Agent ID. Optional run input payload. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents/doc-abc123/agents/agent_abc123/run \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "prompt": "Extract key fields" } }' ``` # Authentication Source: https://docs.okrapdf.com/api-reference/authentication Authenticate API requests with your okraPDF API key. ## API Keys All API requests require an API key. Generate keys in your dashboard: 1. Go to [app.okrapdf.com/settings](https://app.okrapdf.com/settings?tab=api-keys) 2. Click **Create API Key** 3. Copy the key (starts with `okra_`) API keys grant full access to your account. Never expose them in client-side code or public repositories. ## Passing your key Use one of these two methods: ### Bearer token (recommended) ```bash theme={null} curl https://api.okrapdf.com/v1/documents \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Header ```bash theme={null} curl https://api.okrapdf.com/v1/documents \ -H "x-api-key: okra_YOUR_KEY" ``` ## Security best practices * Store keys in environment variables, not in code * Use different keys for development and production * Rotate keys periodically * Revoke keys immediately if compromised For route-level access boundaries, see [Security Model](/api-reference/security-model). ```bash theme={null} # .env OKRA_API_KEY=okra_YOUR_KEY ``` ```python theme={null} import os import requests resp = requests.get( "https://api.okrapdf.com/v1/documents", headers={"Authorization": f"Bearer {os.environ['OKRA_API_KEY']}"}, ) ``` ## Error responses Invalid or missing API keys return a `401` status: ```json theme={null} { "error": { "code": "UNAUTHORIZED", "message": "Invalid or revoked API key." } } ``` # Add Documents to Collection Source: https://docs.okrapdf.com/api-reference/collections/add-documents POST /v1/collections/{id}/documents Add one or more documents to an existing collection. ## Overview Adds documents to a collection by ID. Documents already in the collection are silently skipped. ## Request Collection ID (`col-...`) or collection name. Array of document IDs to add. Must contain at least one ID. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611/documents \ -H "Authorization: Bearer okra_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"document_ids": ["doc-abc123", "doc-def456"]}' ``` ### Response (200) ```json theme={null} { "ok": true, "added": 2 } ``` # Clear Collection Cache Source: https://docs.okrapdf.com/api-reference/collections/clear-cache DELETE /v1/collections/{id}/cache Purge cached query results for a collection. ## Overview Purges all cached query results for a collection. Useful after adding or removing documents to ensure fresh answers. ## Request Collection ID (`col-...`) or collection name. ```bash theme={null} curl -X DELETE https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611/cache \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "ok": true } ``` # Create Collection Source: https://docs.okrapdf.com/api-reference/collections/create-collection POST /v1/collections Create a new named collection, optionally seeded with documents. ## Overview Creates a new collection. You can optionally include document IDs to add at creation time. ## Request Display name for the collection. Optional description of the collection's purpose. Document IDs to seed into the collection. IDs already present are silently skipped. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/collections \ -H "Authorization: Bearer okra_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Q4 Earnings", "description": "Quarterly earnings reports", "document_ids": ["doc-abc123", "doc-def456"] }' ``` ### Response (201) ```json theme={null} { "id": "col-40da068481cf4f248853507cba6be611", "name": "Q4 Earnings", "description": "Quarterly earnings reports", "visibility": "private", "created_at": "2025-01-15T08:30:00Z", "document_count": 2 } ``` # Delete Collection Source: https://docs.okrapdf.com/api-reference/collections/delete-collection DELETE /v1/collections/{id} Delete a collection. Documents are preserved. ## Overview Deletes a collection. Only the grouping is removed -- all member documents remain in your account. ## Request Collection ID (`col-...`) or collection name. ```bash theme={null} curl -X DELETE https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611 \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "ok": true } ``` # Export Collection Source: https://docs.okrapdf.com/api-reference/collections/export-collection GET /v1/collections/{id}/export Export pre-computed markdown for every document in a collection. ## Overview Exports markdown content for all documents in a collection. Supports NDJSON streaming (default) or a zip archive. ## Request Collection ID (`col-...`) or collection name. `markdown` (default, NDJSON stream) or `zip` (one `.md` file per document). ```bash theme={null} # NDJSON event stream curl -N "https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611/export?format=markdown" \ -H "Authorization: Bearer okra_YOUR_KEY" # Zip archive curl -L "https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611/export?format=zip" \ -H "Authorization: Bearer okra_YOUR_KEY" \ -o collection-export.zip ``` ### NDJSON Event Shapes **`start`** -- first event in the stream: ```json theme={null} {"type":"start","doc_count":3,"format":"markdown"} ``` **`result`** -- one per document: ```json theme={null} { "type": "result", "doc_id": "doc-abc123", "file_name": "10k.pdf", "page_count": 2, "pages": [ {"pageNumber": 1, "content": "# Page 1 markdown", "vendor": "okra"}, {"pageNumber": 2, "content": "# Page 2 markdown", "vendor": "okra"} ] } ``` **`done`** -- final success event: ```json theme={null} {"type":"done","completed":3,"failed":0,"total_pages":12} ``` **`error`** -- terminal failure: ```json theme={null} {"type":"error","error":"Collection export failed"} ``` # Get Collection Source: https://docs.okrapdf.com/api-reference/collections/get-collection GET /v1/collections/{id} Retrieve a collection and its document list. ## Overview Returns collection metadata along with the full list of member documents and their processing status. ## Request Collection ID (`col-...`) or collection name. ```bash theme={null} curl https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611 \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "id": "col-40da068481cf4f248853507cba6be611", "name": "Q4 Earnings", "description": "Quarterly earnings reports", "visibility": "private", "created_at": "2025-01-15T08:30:00Z", "document_count": 2, "documents": [ { "id": "doc-abc123", "added_at": "2025-01-15T08:31:00Z", "file_name": "10k.pdf", "phase": "complete", "pages_total": 42, "total_nodes": 318, "source": "upload" } ] } ``` # List Collections Source: https://docs.okrapdf.com/api-reference/collections/list-collections GET /v1/collections Retrieve all collections owned by the authenticated API key. ## Overview Returns an array of all collections belonging to the authenticated key, including document counts. ## Request No parameters required. ```bash theme={null} curl https://api.okrapdf.com/v1/collections \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "collections": [ { "id": "col-40da068481cf4f248853507cba6be611", "name": "Q4 Earnings", "description": "Quarterly earnings reports", "visibility": "private", "created_at": "2025-01-15T08:30:00Z", "document_count": 12 } ] } ``` # Query Collection Source: https://docs.okrapdf.com/api-reference/collections/query-collection POST /v1/collections/{id}/query Run a natural-language query across all documents in a collection. ## Overview Queries all documents in a collection using natural language. Supports optional streaming for real-time responses. ## Request Collection ID (`col-...`) or collection name. Natural-language question to ask across the collection. When `true`, returns a streaming SSE response. Default `false`. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611/query \ -H "Authorization: Bearer okra_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "What was total revenue in Q4?"}' ``` ### Response (200) ```json theme={null} { "answer": "Total revenue in Q4 was $4.2B, a 12% increase year-over-year.", "sources": [ { "doc_id": "doc-abc123", "file_name": "10k.pdf", "page": 15 } ] } ``` # Remove Documents from Collection Source: https://docs.okrapdf.com/api-reference/collections/remove-documents DELETE /v1/collections/{id}/documents Remove one or more documents from a collection. ## Overview Removes documents from a collection. The documents themselves are not deleted from your account. ## Request Collection ID (`col-...`) or collection name. Array of document IDs to remove. Must contain at least one ID. ```bash theme={null} curl -X DELETE https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611/documents \ -H "Authorization: Bearer okra_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"document_ids": ["doc-abc123"]}' ``` ### Response (200) ```json theme={null} { "ok": true, "removed": 1 } ``` # Update Collection Source: https://docs.okrapdf.com/api-reference/collections/update-collection PATCH /v1/collections/{id} Update a collection's name, description, or visibility. ## Overview Partially updates collection metadata. Only provided fields are changed. ## Request Collection ID (`col-...`) or collection name. New display name. New description. `private` or `public`. ```bash theme={null} curl -X PATCH https://api.okrapdf.com/v1/collections/col-40da068481cf4f248853507cba6be611 \ -H "Authorization: Bearer okra_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"visibility": "public"}' ``` ### Response (200) ```json theme={null} { "ok": true } ``` # Get Company Source: https://docs.okrapdf.com/api-reference/companies/get-company GET /v1/companies/{exchange}/{ticker} Retrieve details for a specific company. ## Overview Returns details for a single company identified by exchange and ticker. No authentication required. ## Request Stock exchange code (e.g. `NASDAQ`). Company ticker symbol (e.g. `AAPL`). ```bash theme={null} curl "https://api.okrapdf.com/v1/companies/NASDAQ/AAPL" ``` ### Response ```json theme={null} { "exchange": "NASDAQ", "ticker": "AAPL", "name": "Apple Inc." } ``` # List Companies Source: https://docs.okrapdf.com/api-reference/companies/list-companies GET /v1/companies List all companies with available filings, optionally filtered by exchange. ## Overview Returns a list of companies that have filings available. Optionally filter by stock exchange. No authentication required. ## Request Filter by stock exchange code (e.g. `NYSE`, `NASDAQ`). ```bash theme={null} curl "https://api.okrapdf.com/v1/companies?exchange=NASDAQ" ``` ### Response ```json theme={null} { "companies": [ { "exchange": "NASDAQ", "ticker": "AAPL", "name": "Apple Inc." }, { "exchange": "NASDAQ", "ticker": "MSFT", "name": "Microsoft Corporation" } ] } ``` # Image to PDF Source: https://docs.okrapdf.com/api-reference/conversions/image-to-pdf POST /v1/conversions/image-to-pdf Create a hosted PDF from a PNG or JPEG. ## Overview Stores a PNG or JPEG from multipart upload or source URL as a private file asset, then publishes an immutable PDF derivative with preview and download URLs. PNG or JPEG file when using multipart form data. Source image URL when using JSON. Optional hosted PDF namespace. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/conversions/image-to-pdf \ -H "Authorization: Bearer $OKRA_API_KEY" \ -F "file=@scan.png" \ -F "namespace=scan-as-pdf" ``` # Access Policy Source: https://docs.okrapdf.com/api-reference/documents/access-policy PUT /v1/documents/{id}/config Control who can query, read, and manage a document. ## Overview Every document has an access policy that controls who can interact with it. The policy uses a deny-by-default model with explicit grants. ## Policy shape ```json theme={null} { "access": { "default_effect": "deny", "grants": [ { "principal": { "type": "owner" }, "actions": ["admin"] }, { "principal": { "type": "public" }, "actions": ["query", "read_content", "read_meta"] } ] } } ``` ## Principals | Type | Matches | Use case | | --------- | ---------------------------------- | ------------------------------------------------------ | | `owner` | The user who uploaded the document | Full control | | `public` | Any caller, no auth required | Public-facing documents (HKEX filings, shared reports) | | `user` | A specific user ID | Shared with a teammate | | `org` | All members of an org | Org-wide access | | `project` | All keys scoped to a project | Project-level access | ## Actions | Action | What it permits | | ----------------- | --------------------------------------- | | `admin` | All operations (superset) | | `query` | Chat completions, structured extraction | | `read_content` | Page markdown, node content | | `read_meta` | Document status, metadata | | `download_pdf` | Original PDF download | | `update_config` | Change settings and access policy | | `trigger_extract` | Start extraction jobs | | `publish` | Publish to public corpus | | `create_link` | Create share links | | `list_links` | View existing share links | ## Setting the policy ```bash theme={null} curl -X PUT https://api.okrapdf.com/v1/documents/doc-abc123/config \ -H "Authorization: Bearer okra_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "access": { "default_effect": "deny", "grants": [ { "principal": { "type": "owner" }, "actions": ["admin"] }, { "principal": { "type": "public" }, "actions": ["query", "read_content", "read_meta"] } ] } }' ``` ### Response (200) ```json theme={null} { "document_id": "doc-abc123", "config_version": 1, "config": { "access": { "default_effect": "deny", "grants": [ { "principal": { "type": "owner" }, "actions": ["admin"] }, { "principal": { "type": "public" }, "actions": ["query", "read_content", "read_meta"] } ] } } } ``` ## Grant constraints Grants can have optional constraints: ```json theme={null} { "principal": { "type": "user", "id": "user_abc" }, "actions": ["query"], "constraints": { "expires_at": "2026-06-01T00:00:00Z", "not_before": "2026-03-01T00:00:00Z" } } ``` | Constraint | Effect | | ---------------- | ----------------------------------------------------------- | | `expires_at` | Grant stops working after this time | | `not_before` | Grant only active after this time | | `redaction_role` | Applies PII redaction profile (`admin`, `viewer`, `public`) | ## Common patterns ### Public document (anyone can chat) ```json theme={null} { "grants": [ { "principal": { "type": "owner" }, "actions": ["admin"] }, { "principal": { "type": "public" }, "actions": ["query", "read_content", "read_meta"] } ] } ``` ### Org-internal document ```json theme={null} { "grants": [ { "principal": { "type": "owner" }, "actions": ["admin"] }, { "principal": { "type": "org", "id": "org_xyz" }, "actions": ["query", "read_content"] } ] } ``` ### Time-limited share ```json theme={null} { "grants": [ { "principal": { "type": "owner" }, "actions": ["admin"] }, { "principal": { "type": "user", "id": "user_abc" }, "actions": ["query", "read_content"], "constraints": { "expires_at": "2026-04-01T00:00:00Z" } } ] } ``` # Verify Export Audit Source: https://docs.okrapdf.com/api-reference/documents/audit-verify GET /exports/{id}/audit/verify Verify the integrity of a document's audit trail. ## Overview Validates the chain-hash integrity of a document's audit trail. Returns the document log and vendor log for the specified version. Does not require authentication. ## Request Document ID. Version to verify. Defaults to the latest version. ```bash theme={null} curl "https://api.okrapdf.com/exports/doc-abc123/audit/verify?v=3" \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "version": "3", "documentLog": { "valid": true, "entries": 12 }, "vendorLog": { "valid": true, "entries": 5 } } ``` # Chat Completions Source: https://docs.okrapdf.com/api-reference/documents/chat-completions POST /v1/documents/{id}/chat/completions Ask questions about a processed document with the OpenAI-compatible chat shape. ## Overview Runs a chat completion against one document. The model receives document context from okraPDF and can return cited answers when source evidence is available. Document ID. OpenAI-compatible chat messages. Optional model override. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents/doc-abc123/chat/completions \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "What is the total amount due?" } ] }' ``` # Delete Document Source: https://docs.okrapdf.com/api-reference/documents/delete-document DELETE /v1/documents/{id} Permanently delete a document and all associated data. ## Overview Permanently deletes a document, its extracted content, page images, and exports. This action cannot be undone. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. ```bash theme={null} curl -X DELETE https://api.okrapdf.com/v1/documents/doc-abc123 \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "deleted": true, "id": "doc-abc123" } ``` # Download Original PDF Source: https://docs.okrapdf.com/api-reference/documents/download GET /v1/documents/{id}/original.pdf Download the original uploaded PDF. ## Overview Stream the original PDF that was uploaded for this document. Served from R2 with CDN caching. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. ```bash theme={null} curl -O https://api.okrapdf.com/v1/documents/doc-abc123/original.pdf \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response Returns the raw PDF binary with `Content-Type: application/pdf`. # Export Document Source: https://docs.okrapdf.com/api-reference/documents/export GET /exports/{id}/{format} Download a pre-formatted export of a document. ## Overview Returns a document export in the requested format. Does not require authentication for public documents. ## Request Document ID. Export format: `snapshot`, `markdown`, `excel`, `docx`, or `audit`. ```bash theme={null} curl https://api.okrapdf.com/exports/doc-abc123/markdown \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) Response content type varies by format: * `snapshot` -- `application/json` * `markdown` -- `text/markdown` * `excel` -- `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` * `docx` -- `application/vnd.openxmlformats-officedocument.wordprocessingml.document` * `audit` -- `application/json` # Get Full JSON Source: https://docs.okrapdf.com/api-reference/documents/full-json GET /v1/documents/{id}/full.json Retrieve the entire document content as structured JSON. ## Overview Returns the full extracted document content as a single JSON object. Does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/full.json \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "content": "{ ... full document JSON ... }" } ``` # Get Full Markdown Source: https://docs.okrapdf.com/api-reference/documents/full-markdown GET /v1/documents/{id}/full.md Retrieve the entire document content as markdown. ## Overview Returns the full extracted document content as a single markdown string. Does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/full.md \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) Returns `text/markdown` content type with the full document as markdown text. ``` # Annual Report 2024 ## Executive Summary Revenue grew 15% year-over-year... ``` # Get Document Config Source: https://docs.okrapdf.com/api-reference/documents/get-config GET /v1/documents/{id}/config Retrieve the workflow configuration for a document. ## Overview Returns the current workflow configuration for a document, including processing strategy and capability flags. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/config \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "strategy": "auto", "page_images": "eager", "capabilities": {} } ``` # Get Figure Source: https://docs.okrapdf.com/api-reference/documents/get-figure GET /v1/documents/{id}/entities/figures/{index} Retrieve a specific figure by index. ## Overview Returns a specific figure node from the document by its 0-based index. Does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. 0-based figure index. ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/entities/figures/0 \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "type": "figure", "value": "Figure 1: Revenue breakdown by segment" } ``` # Get Page Content Source: https://docs.okrapdf.com/api-reference/documents/get-page GET /v1/documents/{id}/pages/{page_number} Retrieve extracted content for a single page. ## Overview Returns the extracted content for a specific page as JSON. Does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. 1-based page number. ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/pages/1 \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "page": 1, "content": "# Annual Report\n\nThis document summarizes..." } ``` # Get Page Markdown Source: https://docs.okrapdf.com/api-reference/documents/get-page-markdown GET /v1/documents/{id}/pages/{page_number}/markdown Retrieve a single page as raw markdown text. ## Overview Returns the extracted content for a specific page as raw markdown. Does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. 1-based page number. ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/pages/1/markdown \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) Returns `text/markdown` content type with the page content as markdown. ``` # Annual Report This document summarizes the fiscal year... ``` # Get Document Status Source: https://docs.okrapdf.com/api-reference/documents/get-status GET /v1/documents/{id} Retrieve the current status and metadata for a document. ## Overview Returns the current processing status, page count, and metadata for a document. This endpoint does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123 \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "id": "doc-abc123", "status": "completed", "file_name": "annual-report.pdf", "total_pages": 42, "pages_completed": 42, "inserted_at": "2025-01-15T08:30:00Z", "updated_at": "2025-01-15T08:32:00Z", "is_public": false } ``` # Get Table Source: https://docs.okrapdf.com/api-reference/documents/get-table GET /v1/documents/{id}/entities/tables/{index} Retrieve a specific table by index in multiple formats. ## Overview Returns a specific table from the document. Use the `format` query parameter to choose the output format. **Multiple formats.** Use the `format` query parameter to get the table as `json`, `csv`, `html`, or `markdown`. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. 0-based table index. Output format: `json`, `csv`, `html`, or `markdown`. Defaults to `json`. ```bash theme={null} curl "https://api.okrapdf.com/v1/documents/doc-abc123/entities/tables/0?format=csv" \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) Response content type varies by format. For `json`: ```json theme={null} { "type": "table", "value": "| Header 1 | Header 2 |\n|---|---|\n| A | B |" } ``` # Ingest Vendor Output Source: https://docs.okrapdf.com/api-reference/documents/ingest POST /v1/documents/ingest Push raw vendor extraction output into a document. ## Overview Push raw vendor output (OCR, layout, etc.) into a document. Each call appends a new record -- previous data is never overwritten. **Append-only.** Each ingest call appends a new record. Previous data is never overwritten. ## Request Target document ID (e.g. `doc-abc123`). Vendor identifier (e.g. `azure_di`, `textract`). Raw vendor output. Any JSON shape accepted. SHA-256 hash of the source PDF for optimistic concurrency. Returns 409 on mismatch. Capability configuration including `vlm_qwen`, `structural_check`, `sandbox_verify`, `search`, `phases`, and `middleware`. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents/ingest \ -H "Authorization: Bearer okra_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "document_id": "doc-abc123", "vendor": "azure_di", "payload": { "pages": [...] } }' ``` ### Response (200) ```json theme={null} { "ok": true, "seq": 3, "document_id": "doc-abc123" } ``` # List Documents Source: https://docs.okrapdf.com/api-reference/documents/list-documents GET /v1/documents List documents owned by the authenticated API key. ## Overview Returns a paginated list of documents associated with the authenticated API key. ## Request Max results to return (1-100, default 20). Cursor: return results after this document ID. Cursor: return results before this document ID. Sort order by `inserted_at`: `asc` or `desc`. ```bash theme={null} curl "https://api.okrapdf.com/v1/documents?limit=10&order=desc" \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "data": [ { "id": "doc-abc123", "status": "completed", "file_name": "annual-report.pdf", "total_pages": 42, "pages_completed": 42, "inserted_at": "2025-01-15T08:30:00Z", "updated_at": "2025-01-15T08:32:00Z", "thumbnail_url": "https://res.okrapdf.com/v1/documents/doc-abc123/pg_1.png", "is_public": false, "source": "api" } ], "has_more": false } ``` # List Figures Source: https://docs.okrapdf.com/api-reference/documents/list-figures GET /v1/documents/{id}/entities/figures List all figures extracted from a document. ## Overview Returns all figure nodes extracted from a document. Does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. Max number of figures to return. Number of figures to skip (for pagination). ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/entities/figures \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "nodes": [ { "type": "figure", "value": "Figure 1: Revenue breakdown by segment" } ] } ``` # List Tables Source: https://docs.okrapdf.com/api-reference/documents/list-tables GET /v1/documents/{id}/entities/tables List all tables extracted from a document. ## Overview Returns all table nodes extracted from a document. Does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. Max number of tables to return. Number of tables to skip (for pagination). ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/entities/tables \ -H "Authorization: Bearer okra_YOUR_KEY" ``` ### Response (200) ```json theme={null} { "nodes": [ { "type": "table", "value": "| Header 1 | Header 2 |\n|---|---|\n| A | B |" } ] } ``` # Get Page Image Source: https://docs.okrapdf.com/api-reference/documents/page-image GET /v1/documents/{id}/pages/{page_number}/image.png Retrieve a rendered PNG image of a document page. ## Overview Returns a PNG rendering of the specified page. The first request for a lazily-rendered page may take \~12s; subsequent requests serve from cache (\~0.3s). Does not require authentication for public documents. ## Request Document ID (e.g. `doc-abc123`) or 6-char short hash. 1-based page number. ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123/pages/1/image.png \ -H "Authorization: Bearer okra_YOUR_KEY" \ --output page1.png ``` ### Response (200) Returns `image/png` binary data. # Structured Output Source: https://docs.okrapdf.com/api-reference/documents/structured-output POST /v1/documents/{id}/structured-output Extract JSON from a document using a JSON Schema. ## Overview Extracts data from a processed document and validates the result against a JSON Schema. Document ID. Natural-language extraction instruction. JSON Schema for the desired output. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents/doc-abc123/structured-output \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Extract invoice fields.", "schema": { "type": "object", "properties": { "vendor": { "type": "string" }, "total": { "type": "number" } }, "required": ["vendor", "total"] } }' ``` # Upload PDF (Multipart) Source: https://docs.okrapdf.com/api-reference/documents/upload-multipart POST /v1/documents Upload a PDF file using multipart form data. ## Overview Upload a PDF file directly using `multipart/form-data`. The document is assigned an ID and queued for processing. ## Request Page image rendering strategy: `eager` (default, render all pages), `cover` (page 1 only), or `none`. `lazy` is accepted as a deprecated alias for `eager`. Processing strategy hint. The PDF file to upload. Comma-separated capability flags. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents \ -H "Authorization: Bearer okra_YOUR_KEY" \ -F "file=@report.pdf" \ -F "capabilities=vlm_qwen" ``` ### Response (202) ```json theme={null} { "id": "doc-abc123", "status": "queued" } ``` # Errors Source: https://docs.okrapdf.com/api-reference/errors Standard error codes and how to handle them. ## Error format All errors return a consistent JSON shape: ```json theme={null} { "error": { "code": "BAD_REQUEST", "message": "Human-readable description of the problem" } } ``` ## Error codes | Code | HTTP Status | Description | | -------------------------- | ----------- | ----------------------------------------------------------------- | | `BAD_REQUEST` | 400 | Invalid request body or parameters | | `UNAUTHORIZED` | 401 | Missing or invalid API key | | `FORBIDDEN` | 403 | Valid key but not authorized for this resource | | `NOT_FOUND` | 404 | Document or resource does not exist | | `CONFLICT` | 409 | Resource state conflict | | `SCHEMA_VALIDATION_FAILED` | 422 | Request was well-formed but semantically invalid | | `RATE_LIMITED` | 429 | Too many requests - see [rate limits](/api-reference/rate-limits) | | `INTERNAL_ERROR` | 500 | Unexpected server error | | `TIMEOUT` | 504 | The operation timed out | ## Handling errors ### Retry strategy For transient errors (`429`, `500`, `502`, `503`, `504`), use exponential backoff: ```python theme={null} import time import requests def api_call_with_retry(url, headers, max_retries=3): for attempt in range(max_retries): resp = requests.get(url, headers=headers) if resp.status_code == 429: retry_after = int(resp.headers.get("Retry-After", 5)) time.sleep(retry_after) continue if resp.status_code >= 500: time.sleep(2 ** attempt) continue return resp raise Exception(f"Failed after {max_retries} retries") ``` ### Non-retryable errors | Code | Action | | ----- | ---------------------------------------------- | | `400` | Fix your request body or parameters | | `401` | Check your API key | | `403` | Verify you own the resource | | `404` | Verify the document ID exists | | `422` | Check request schema against the API reference | ## Structured output errors The `/v1/documents/{id}/structured-output` endpoint returns specific extraction errors: | Code | HTTP Status | Description | | -------------------------- | ----------- | -------------------------------------------------------------------------------------------------------- | | `SCHEMA_VALIDATION_FAILED` | 422 | Extracted data didn't match your JSON schema. Check field types, required fields, and nesting. | | `EXTRACTION_BLOCKED` | 422 | The model couldn't extract data — document has no pages, parsing failed, or all queries returned errors. | | `TIMEOUT` | 504 | Extraction exceeded the time limit (default 45s, MCP uses 120s). Simplify the schema or use page ranges. | | `DOCUMENT_NOT_FOUND` | 404 | Document ID does not exist or has not finished processing. Check document status first. | ### Example error response ```json theme={null} { "error": { "message": "Structured output timed out", "type": "server_error", "details": { "timeoutMs": 120000 } } } ``` ### Tips for reliable extraction * **Keep schemas flat** when possible — fewer nested objects means faster extraction * **Use string types** for financial values (e.g. `"$215,938 million"`) rather than numbers to avoid parsing ambiguity * **Check document status** before extracting — `phase: "complete"` is required # Download File Bytes Source: https://docs.okrapdf.com/api-reference/files/download-file GET /v1/files/{id}/bytes Download private file bytes. ## Overview Downloads the original private file bytes. Requires authentication. File ID. ```bash theme={null} curl https://api.okrapdf.com/v1/files/file_abc123/bytes \ -H "Authorization: Bearer $OKRA_API_KEY" \ -o report.pdf ``` # Finalize Direct Upload Source: https://docs.okrapdf.com/api-reference/files/finalize-file POST /v1/files/finalize Finalize a direct-to-storage PDF upload. ## Overview Call this after PUTing bytes to the signed `upload_url` returned by `/v1/files/presign`. Upload session ID returned by `/v1/files/presign`. Original filename. Storage key returned by the presign response. SHA-256 digest of the uploaded file. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/files/finalize \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "upl_abc123", "fileName": "report.pdf", "r2Key": "uploads/...", "sha256": "..." }' ``` # Get File Source: https://docs.okrapdf.com/api-reference/files/get-file GET /v1/files/{id} Get file metadata for a passive PDF asset. ## Overview Returns metadata for a private file asset. File ID. ```bash theme={null} curl https://api.okrapdf.com/v1/files/file_abc123 \ -H "Authorization: Bearer $OKRA_API_KEY" ``` # List Files Source: https://docs.okrapdf.com/api-reference/files/list-files GET /v1/files List passive PDF file assets. ## Overview Files are passive private assets. They do not automatically start document parsing. Use them when you want to upload once and later host, convert, or run a workflow. Maximum number of files to return. Pagination cursor from a previous response. ```bash theme={null} curl https://api.okrapdf.com/v1/files \ -H "Authorization: Bearer $OKRA_API_KEY" ``` # Create Direct Upload Source: https://docs.okrapdf.com/api-reference/files/presign-file POST /v1/files/presign Create a direct-to-storage upload session for a PDF. ## Overview Use this for larger PDFs or browser/server uploads where you want to PUT bytes directly to the signed storage URL, then finalize the file with `/v1/files/finalize`. Original filename. File size in bytes. SHA-256 digest of the file bytes. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/files/presign \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "fileName": "report.pdf", "fileSize": 10485760, "sha256": "..." }' ``` # Upload File Source: https://docs.okrapdf.com/api-reference/files/upload-file POST /v1/files Upload a passive PDF file asset. ## Overview Upload a PDF as a private file asset without starting a document workflow. For files larger than the multipart threshold, use [Create Direct Upload](/api-reference/files/presign-file) and [Finalize Direct Upload](/api-reference/files/finalize-file). PDF file to upload. Optional JSON document config to attach to the file metadata. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/files \ -H "Authorization: Bearer $OKRA_API_KEY" \ -F "file=@report.pdf" ``` ### Response ```json theme={null} { "object": "file", "id": "file_abc123", "file_name": "report.pdf", "workflow_bound": false } ``` # Get Filing Source: https://docs.okrapdf.com/api-reference/filings/get-filing GET /v1/filings/{exchange}/{ticker}/{slug} Retrieve details for a specific SEC filing. ## Overview Returns metadata for a single SEC filing identified by exchange, ticker, and slug. No authentication required. ## Request Stock exchange code (e.g. `NASDAQ`). Company ticker symbol (e.g. `AAPL`). Filing slug, typically the SEC accession number (e.g. `0000320193-23-000106`). ```bash theme={null} curl "https://api.okrapdf.com/v1/filings/NASDAQ/AAPL/0000320193-23-000106" ``` ### Response ```json theme={null} { "exchange": "NASDAQ", "ticker": "AAPL", "slug": "0000320193-23-000106", "type": "10-K", "filed_at": "2023-11-03" } ``` # Get Filing Audit Trail Source: https://docs.okrapdf.com/api-reference/filings/get-filing-audit GET /v1/filings/{exchange}/{ticker}/{slug}/audit Retrieve the processing audit trail for a filing. ## Overview Returns the audit trail showing all processing steps and their outcomes for a filing. No authentication required. ## Request Stock exchange code (e.g. `NASDAQ`). Company ticker symbol (e.g. `AAPL`). Filing slug, typically the SEC accession number (e.g. `0000320193-23-000106`). ```bash theme={null} curl "https://api.okrapdf.com/v1/filings/NASDAQ/AAPL/0000320193-23-000106/audit" ``` ### Response ```json theme={null} { "audit": [ { "step": "upload", "status": "complete", "timestamp": "2024-01-15T10:30:00Z" }, { "step": "ocr", "status": "complete", "timestamp": "2024-01-15T10:31:12Z" } ] } ``` # List Filing Nodes Source: https://docs.okrapdf.com/api-reference/filings/get-filing-nodes GET /v1/filings/{exchange}/{ticker}/{slug}/nodes List extracted nodes (tables, text blocks, etc.) in a filing. ## Overview Returns structured nodes extracted from a filing. Filter by node type or page, with pagination support. No authentication required. ## Request Stock exchange code (e.g. `NASDAQ`). Company ticker symbol (e.g. `AAPL`). Filing slug, typically the SEC accession number (e.g. `0000320193-23-000106`). Filter by node type (e.g. `table`, `text`, `title`). Filter nodes to a specific page number. Maximum number of nodes to return. Number of nodes to skip for pagination. ```bash theme={null} curl "https://api.okrapdf.com/v1/filings/NASDAQ/AAPL/0000320193-23-000106/nodes?type=table&limit=10" ``` ### Response ```json theme={null} { "nodes": [ { "id": "node-abc123", "type": "table", "page": 1, "content": "..." } ], "total": 42 } ``` # Get Filing Page Source: https://docs.okrapdf.com/api-reference/filings/get-filing-page GET /v1/filings/{exchange}/{ticker}/{slug}/page/{page_number} Retrieve content for a specific page in a filing. ## Overview Returns the content of a single page within a filing by its 1-based page number. No authentication required. ## Request Stock exchange code (e.g. `NASDAQ`). Company ticker symbol (e.g. `AAPL`). Filing slug, typically the SEC accession number (e.g. `0000320193-23-000106`). 1-based page number. ```bash theme={null} curl "https://api.okrapdf.com/v1/filings/NASDAQ/AAPL/0000320193-23-000106/page/1" ``` ### Response ```json theme={null} { "page_number": 1, "width": 612, "height": 792, "content": "..." } ``` # List Filing Pages Source: https://docs.okrapdf.com/api-reference/filings/get-filing-pages GET /v1/filings/{exchange}/{ticker}/{slug}/pages List all pages in a filing. ## Overview Returns a list of all pages within a specific SEC filing. No authentication required. ## Request Stock exchange code (e.g. `NASDAQ`). Company ticker symbol (e.g. `AAPL`). Filing slug, typically the SEC accession number (e.g. `0000320193-23-000106`). ```bash theme={null} curl "https://api.okrapdf.com/v1/filings/NASDAQ/AAPL/0000320193-23-000106/pages" ``` ### Response ```json theme={null} { "pages": [ { "page_number": 1, "width": 612, "height": 792 }, { "page_number": 2, "width": 612, "height": 792 } ] } ``` # Get Filing Status Source: https://docs.okrapdf.com/api-reference/filings/get-filing-status GET /v1/filings/{exchange}/{ticker}/{slug}/status Check the processing status of a filing. ## Overview Returns the current processing status for a filing. No authentication required. ## Request Stock exchange code (e.g. `NASDAQ`). Company ticker symbol (e.g. `AAPL`). Filing slug, typically the SEC accession number (e.g. `0000320193-23-000106`). ```bash theme={null} curl "https://api.okrapdf.com/v1/filings/NASDAQ/AAPL/0000320193-23-000106/status" ``` ### Response ```json theme={null} { "phase": "complete", "total_pages": 78, "total_nodes": 215 } ``` # List Filings Source: https://docs.okrapdf.com/api-reference/filings/list-filings GET /v1/filings List all available SEC filings, optionally filtered by exchange, ticker, or type. ## Overview Returns a paginated list of SEC filings. Filter by exchange, ticker, or filing type. No authentication required. ## Request Stock exchange code (e.g. `NYSE`, `NASDAQ`). Company ticker symbol (e.g. `AAPL`, `MSFT`). Filing type (e.g. `10-K`, `10-Q`, `8-K`). Maximum number of filings to return. ```bash theme={null} curl "https://api.okrapdf.com/v1/filings?exchange=NASDAQ&ticker=AAPL&type=10-K" ``` ### Response ```json theme={null} { "filings": [ { "exchange": "NASDAQ", "ticker": "AAPL", "slug": "0000320193-23-000106", "type": "10-K", "filed_at": "2023-11-03" } ] } ``` # Search Filing Source: https://docs.okrapdf.com/api-reference/filings/search-filing GET /v1/filings/{exchange}/{ticker}/{slug}/search Full-text search within a specific filing. ## Overview Search for text within a specific filing. Returns matching nodes and their locations. No authentication required. ## Request Stock exchange code (e.g. `NASDAQ`). Company ticker symbol (e.g. `AAPL`). Filing slug, typically the SEC accession number (e.g. `0000320193-23-000106`). Search query string. ```bash theme={null} curl "https://api.okrapdf.com/v1/filings/NASDAQ/AAPL/0000320193-23-000106/search?q=revenue" ``` ### Response ```json theme={null} { "results": [ { "node_id": "node-abc123", "page": 12, "snippet": "...total revenue of $383.3 billion..." } ] } ``` # Create Hosted PDF Source: https://docs.okrapdf.com/api-reference/host/create-hosted-pdf POST /v1/host Publish a PDF file to a clean okrapdf.dev hostname. ## Overview Publish an existing PDF from `/v1/files` or `/v1/documents` as `https://{namespace}.okrapdf.dev`. Internal storage keys such as `original.pdf` are not exposed. Source file or document reference. Use a file ID for passive assets or a document ID for parsed documents. Desired DNS-label namespace. If omitted, okraPDF generates one. Human-readable title for the hosted PDF. Optional access settings such as disabled, unlisted, expiry, password, download availability, and indexing. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/host \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "source": { "file_id": "file_abc123" }, "namespace": "acme-report", "title": "Acme Report" }' ``` ### Response ```json theme={null} { "namespace": "acme-report", "deployment": { "url": "https://acme-report.okrapdf.dev" } } ``` # Get Hosted PDF Source: https://docs.okrapdf.com/api-reference/host/get-hosted-pdf GET /v1/host/{namespace} Retrieve hosted PDF deployment metadata. ## Overview Returns metadata for a hosted PDF deployment. Hosted PDF namespace. ```bash theme={null} curl https://api.okrapdf.com/v1/host/acme-report \ -H "Authorization: Bearer $OKRA_API_KEY" ``` # List Hosted PDFs Source: https://docs.okrapdf.com/api-reference/host/list-hosted-pdfs GET /v1/host List hosted PDF deployments. ## Overview Returns hosted PDF deployments owned by the authenticated account. ```bash theme={null} curl https://api.okrapdf.com/v1/host \ -H "Authorization: Bearer $OKRA_API_KEY" ``` # Update Hosted PDF Source: https://docs.okrapdf.com/api-reference/host/update-hosted-pdf PATCH /v1/host/{namespace} Update title, source, or access settings for a hosted PDF. ## Overview Update a hosted PDF title, repoint an owned deployment hostname to another PDF with `replace: true`, or change access settings such as unlisted, disabled, expiry, password, download availability, and indexing. Hosted PDF namespace. New title. New source file or document reference. Set true when repointing the namespace to another source. Access settings. ```bash theme={null} curl -X PATCH https://api.okrapdf.com/v1/host/acme-report \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Acme Report v2" }' ``` # Introduction Source: https://docs.okrapdf.com/api-reference/introduction Upload, host, extract, and query PDFs with the Okra API. ## Base URL ```text theme={null} https://api.okrapdf.com ``` The Mintlify API reference is backed by the live OpenAPI 3.1 spec from `https://api.okrapdf.com/openapi.json` (version `1.14.0`). ## Authentication Use a Bearer token for authenticated endpoints: ```bash theme={null} Authorization: Bearer okra_sk_YOUR_KEY ``` Secret keys use the `okra_sk_` prefix. Browser-facing publishable keys use `okra_pk_`. Create and rotate keys in [app.okrapdf.com/settings](https://app.okrapdf.com/settings?tab=api-keys). ## First request ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents \ -H "Authorization: Bearer $OKRA_API_KEY" \ -F "file=@report.pdf" ``` Response: ```json theme={null} { "id": "doc-abc123", "status": "queued" } ``` ## Current surfaces | Surface | Endpoint family | Use it for | | ----------- | --------------------------- | ------------------------------------------------------------------------------ | | Files | `/v1/files` | Store passive private PDF assets before running a workflow or hosting. | | Documents | `/v1/documents` | Upload, parse, read markdown/pages/entities, chat, and manage document config. | | Host | `/v1/host` | Publish clean `*.okrapdf.dev` PDF deployments from files or documents. | | Conversions | `/v1/conversions` | One-call file conversion flows such as image to hosted PDF. | | MCP | `/mcp` | Remote agent tools and visual MCP Apps. | | Workflows | `/v1/workflows`, `/v1/runs` | Built-in document workflows and private-beta dynamic agent workflows. | | Collections | `/v1/collections` | Group documents and run multi-document queries or exports. | | Agents | `/v1/agents` | Register and run reusable JSON-configured document agents. | ## Common document endpoints | Method | Path | Description | | ------ | -------------------------------------------------- | ----------------------------------------------------- | | POST | `/v1/documents` | Upload a document with multipart form data. | | GET | `/v1/documents/{id}` | Get document status and metadata. | | GET | `/v1/documents/{id}/full.md` | Read the full document as markdown. | | GET | `/v1/documents/{id}/pages/{page_number}/image.png` | Render a page image. | | GET | `/v1/documents/{id}/entities/tables` | List extracted tables. | | POST | `/v1/documents/{id}/structured-output` | Extract JSON using a schema. | | POST | `/v1/documents/{id}/chat/completions` | Ask questions using the OpenAI-compatible chat shape. | ## Errors Errors use a structured JSON envelope: ```json theme={null} { "error": { "code": "BAD_REQUEST", "message": "Human-readable description of the problem" } } ``` See [Errors](/api-reference/errors) for common codes and retry behavior. # Quickstart Source: https://docs.okrapdf.com/api-reference/quickstart Upload and query your first PDF with REST. ## Prerequisites * An okraPDF account: [sign up](https://app.okrapdf.com/sign-up) * An API key: [create one](https://app.okrapdf.com/settings?tab=api-keys) ```bash theme={null} export OKRA_API_KEY=okra_sk_YOUR_KEY ``` ## 1. Upload a document ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents \ -H "Authorization: Bearer $OKRA_API_KEY" \ -F "file=@invoice.pdf" ``` Response: ```json theme={null} { "id": "doc-abc123", "status": "queued" } ``` ## 2. Poll status ```bash theme={null} curl https://api.okrapdf.com/v1/documents/doc-abc123 \ -H "Authorization: Bearer $OKRA_API_KEY" ``` Wait until the document reports a terminal phase such as `complete`, `awaiting_review`, or `error`. ```json theme={null} { "id": "doc-abc123", "phase": "complete", "fileName": "invoice.pdf", "pagesTotal": 3, "pagesCompleted": 3 } ``` ## 3. Read results ```bash theme={null} # Full document markdown curl https://api.okrapdf.com/v1/documents/doc-abc123/full.md \ -H "Authorization: Bearer $OKRA_API_KEY" # Page 1 as markdown curl https://api.okrapdf.com/v1/documents/doc-abc123/pages/1/markdown \ -H "Authorization: Bearer $OKRA_API_KEY" # Extracted tables curl https://api.okrapdf.com/v1/documents/doc-abc123/entities/tables \ -H "Authorization: Bearer $OKRA_API_KEY" ``` ## 4. Ask a cited question ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents/doc-abc123/chat/completions \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "role": "user", "content": "What is the total amount due?" } ] }' ``` ## 5. Extract structured JSON ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/documents/doc-abc123/structured-output \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Extract invoice fields.", "schema": { "type": "object", "properties": { "vendor": { "type": "string" }, "total": { "type": "number" }, "currency": { "type": "string" } }, "required": ["vendor", "total"] } }' ``` ## JavaScript SDK equivalent ```ts theme={null} import { createOkra } from '@okrapdf/sdk'; const okra = createOkra({ apiKey: process.env.OKRA_API_KEY }); const session = await okra.sessions.create('./invoice.pdf', { wait: true }); const { markdown } = await okra.read(session.id); const { answer, sources } = await session.prompt('What is the total amount due?'); console.log(markdown); console.log(answer, sources); ``` # Rate Limits Source: https://docs.okrapdf.com/api-reference/rate-limits API rate limits for okraPDF. ## Limits | Context | Requests/min | Expensive ops/min | | --------------- | ------------ | ----------------- | | Authenticated | 600 | 30 | | Unauthenticated | 60 | 5 | "Expensive ops" include `POST /v1/documents` (uploads), `POST /v1/documents/{id}/structured-output`, and `POST /v1/documents/{id}/chat/completions`. All other endpoints count as standard requests. ## Rate limit headers Every API response includes rate limit information: | Header | Description | | ----------------------- | --------------------------------- | | `X-RateLimit-Limit` | Max requests per window | | `X-RateLimit-Remaining` | Requests remaining | | `X-RateLimit-Reset` | Unix timestamp when window resets | ## When rate limited You receive a `429` response: ```json theme={null} { "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded. Please try again later." } } ``` The `Retry-After` header tells you how many seconds to wait. ## Best practices 1. **Check headers** before hitting limits -- monitor `X-RateLimit-Remaining` 2. **Use exponential backoff** on 429 responses 3. **Batch small PDFs** -- prefer one large job over many small ones 4. **Cache results** -- store extraction results locally after fetching ```python theme={null} import time def respect_rate_limit(response): remaining = int(response.headers.get("X-RateLimit-Remaining", 1)) if remaining <= 1: reset = int(response.headers.get("X-RateLimit-Reset", 0)) wait = max(0, reset - time.time()) time.sleep(wait) ``` # Security Model Source: https://docs.okrapdf.com/api-reference/security-model How authentication and access control work across the API. ## Two layers 1. **Authentication** — who is calling (API key, shared secret, JWT) 2. **Access policy** — what the caller can do on a specific document ## Authentication Every request is authenticated via one of: | Method | Header | Use case | | --------------- | ----------------------------------- | ------------------------- | | API key | `Authorization: Bearer okra_sk_...` | Server-to-server | | Publishable key | `Authorization: Bearer okra_pk_...` | Browser clients | | Shared secret | `x-document-agent-secret: ...` | Internal worker-to-worker | Unauthenticated requests can still interact with documents that have a `public` grant in their access policy. ## Access policy Each document has a deny-by-default access policy with explicit grants. A grant maps a **principal** (who) to **actions** (what). ```json theme={null} { "access": { "default_effect": "deny", "grants": [ { "principal": { "type": "owner" }, "actions": ["admin"] }, { "principal": { "type": "public" }, "actions": ["query", "read_content"] } ] } } ``` See [Access Policy](/api-reference/documents/access-policy) for the full reference. ## Route classes ### Document and source read surface (`/v1/documents/...`) Processed outputs and public-source chat. Access is controlled by API credentials, source resolution, and document grants where applicable. * `GET /v1/documents/{id}` — metadata * `GET /v1/documents/{id}/pages/{page}` — page content * `POST /v1/public/resolve/chat/completions` — public source chat ### Authenticated mutation surface (`/v1/...`) Mutations and configuration require an API key. * `POST /v1/documents` — upload and process a document * `PUT /v1/documents/{id}/config` — set document config and access policy * `POST /v1/files` — upload a passive file asset * `POST /v1/host` — publish a hosted PDF deployment ## Caching * Public routes: `Cache-Control: public` (CDN-safe) * Private routes: `Cache-Control: private` or `no-store` # Run Invoice Extraction Source: https://docs.okrapdf.com/api-reference/workflows/create-invoice-extraction-run POST /v1/workflows/invoice-extraction/runs Start the built-in invoice extraction workflow. ## Overview Starts an invoice-extraction workflow for one or more uploaded files. Parser and model controls are managed by okraPDF. File inputs. Each item must include `file_id`. Optional existing table for results. Quality preset. ```bash theme={null} curl -X POST https://api.okrapdf.com/v1/workflows/invoice-extraction/runs \ -H "Authorization: Bearer $OKRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "inputs": [{ "file_id": "file_abc123" }], "quality": "standard" }' ``` # Get Invoice Extraction Run Source: https://docs.okrapdf.com/api-reference/workflows/get-invoice-extraction-run GET /v1/workflows/invoice-extraction/runs/{run_id} Get invoice extraction run metadata. ## Overview Returns status, quality metadata, input file references, event stream URL, row URL, and export URLs for a run. Invoice extraction run ID. ```bash theme={null} curl https://api.okrapdf.com/v1/workflows/invoice-extraction/runs/run_abc123 \ -H "Authorization: Bearer $OKRA_API_KEY" ``` # Invoice Extraction Source: https://docs.okrapdf.com/api-reference/workflows/invoice-extraction Built-in workflow for extracting invoice fields into reviewable outputs. ## Overview The `invoice-extraction` workflow starts from one or more `/v1/files` inputs, runs okraPDF's built-in invoice processing pipeline, and returns run metadata plus JSON, CSV, XML, and XLSX export URLs. Use this when you want an opinionated workflow instead of a one-off document question. Use [Upload File](/api-reference/files/upload-file) or direct upload. Call [Run Invoice Extraction](/api-reference/workflows/create-invoice-extraction-run) with file IDs. Poll the run, inspect exceptions, and download results. # Invoice Extraction Results Source: https://docs.okrapdf.com/api-reference/workflows/invoice-extraction-results GET /v1/workflows/invoice-extraction/runs/{run_id}/results.json Download invoice extraction results as JSON. ## Overview Downloads normalized JSON results for an invoice extraction run. CSV, XML, and XLSX result endpoints are also available with the same run ID. Invoice extraction run ID. ```bash theme={null} curl https://api.okrapdf.com/v1/workflows/invoice-extraction/runs/run_abc123/results.json \ -H "Authorization: Bearer $OKRA_API_KEY" ``` # List Invoice Extraction Runs Source: https://docs.okrapdf.com/api-reference/workflows/list-invoice-extraction-runs GET /v1/workflows/invoice-extraction/runs List invoice extraction runs for the signed-in account. ## Overview Returns invoice extraction runs indexed for the authenticated account. Maximum number of runs to return. Pagination cursor. ```bash theme={null} curl https://api.okrapdf.com/v1/workflows/invoice-extraction/runs \ -H "Authorization: Bearer $OKRA_API_KEY" ``` # How It Works Source: https://docs.okrapdf.com/architecture A workbench that helps you understand, verify, and manage PDF data ## The Simple Version **Upload a PDF → Understand, verify, and manage the data inside.** okraPDF is a workbench that helps you extract structured data from documents, verify its accuracy, and put it to work. ```mermaid theme={null} flowchart LR A[Your PDF] --> B[okraPDF] B --> C[Understand] B --> D[Verify] B --> E[Manage] subgraph C[Understand] C1[Search] C2[Chat] end subgraph D[Verify] D1[Review] D2[Correct] end subgraph E[Manage] E1[Tables] E2[Charts] E3[Images] E4[Export] end style A fill:#1e293b,color:#f8fafc,stroke:#475569 style B fill:#FFE01B,color:#1e293b,stroke:#E6C800 style C fill:#16a34a,color:#fff,stroke:#15803d style D fill:#7c3aed,color:#fff,stroke:#6d28d9 style E fill:#0369a1,color:#fff,stroke:#0284c7 ``` ## What You Get Search across all pages. Chat with AI that's grounded in your document. Review extracted data side-by-side with the original. Correct errors with AI assistance. Tables, charts, images, footnotes — detected, structured, and exportable. ## Behind the Scenes When you upload a PDF, four things happen automatically: Your file goes directly to encrypted cloud storage. We never store files on local servers. We use [Google's Document AI](https://cloud.google.com/document-ai/docs/processors-list#processor_doc-ocr) to extract text with high accuracy — even from scanned documents and complex layouts. Our AI scans each page for tables, charts, images, footnotes, and signatures. Your document is ready for search, chat, review, and export. **Processing time:** 10-30 seconds for most documents. ## Review & Verify In the review page, you can verify extracted data side-by-side with the original document. AI assists with corrections without hallucinating content. ```mermaid theme={null} flowchart LR A[Extracted Data] --> B[AI Review] C[Original Page] --> B B --> D[Verified Data] style A fill:#1e293b,color:#f8fafc,stroke:#475569 style B fill:#FFE01B,color:#1e293b,stroke:#E6C800 style C fill:#1e293b,color:#f8fafc,stroke:#475569 style D fill:#16a34a,color:#fff,stroke:#15803d ``` **How it works:** * View extracted data alongside the original page image * AI suggests corrections for punctuation and character errors * You approve changes — the AI is constrained to correct, not rewrite ## AI Chat When you chat with your document, we create a private workspace with all your extracted data: ```mermaid theme={null} flowchart LR Q[Ask: What's the revenue in Q3?] --> AI subgraph Workspace["Your Private Workspace"] AI[AI Agent] PDF[Original PDF] T[Tables] C[Charts] TXT[Full Text] end AI --> PDF AI --> T AI --> C AI --> TXT AI --> R[Answer: $4.2M per Table 3 on page 12] style Q fill:#1e293b,color:#f8fafc,stroke:#475569 style R fill:#16a34a,color:#fff,stroke:#15803d style AI fill:#FFE01B,color:#1e293b,stroke:#E6C800 style Workspace fill:#1e3a5f,color:#f8fafc,stroke:#0ea5e9 style PDF fill:#0ea5e9,color:#fff,stroke:#0284c7 style T fill:#0ea5e9,color:#fff,stroke:#0284c7 style C fill:#0ea5e9,color:#fff,stroke:#0284c7 style TXT fill:#0ea5e9,color:#fff,stroke:#0284c7 ``` **What's in your workspace:** * Your original PDF * All extracted tables, charts, and images * Full document text * Isolated from other users ## Security | What We Do | Why It Matters | | ------------------------ | ----------------------------------------------------------- | | Encrypt files at rest | Your documents are protected even if storage is compromised | | Encrypt all transfers | No one can intercept your uploads or downloads | | Isolate AI sessions | Your data never mixes with other users' data | | No training on your data | Your documents are never used to train AI models | # Chat Source: https://docs.okrapdf.com/cli/chat Ask a question about one processed document from the command line. `okra chat` asks a question about a single processed document and returns a cited answer. It requires a document ID via `--doc`. ```bash theme={null} okra chat "What was total revenue?" --doc doc-abc123 ``` `okra chat` is the ergonomic alias for the canonical grounded command [`okra context ask`](/cli/reference). Both answer from bounded, cited context for one document. ## Flags | Flag | Description | | ---------------- | --------------------------------------- | | `--doc ` | Document ID to ask about (**required**) | | `--model ` | Override the model | | `--stream` | Stream response tokens as they arrive | ## Streaming ```bash theme={null} okra chat "Summarize the key findings" --doc doc-abc123 --stream ``` With `--stream`, tokens print as they arrive. In `--json` mode the streamed answer is collected and returned as a single JSON payload. ## Machine-readable output When stdout is not a TTY (or with `--json`), `okra chat` returns the standard envelope with the answer and any citations: ```json theme={null} { "ok": true, "command": "chat", "result": { "answer": "Total revenue was $4.2M for FY2023." }, "cost": { "usd": null }, "citations": [], "next_actions": [] } ``` ## Asking across multiple documents To ask one question across several documents, group them into a collection and use [`okra collections query`](/cli/collections): ```bash theme={null} okra collections query "Q4 Reports" "Compare revenue across companies" ``` For general questions that aren't about a specific document, use a chat client connected via [MCP](/mcp/overview) rather than `okra chat`, which always operates on one document. # Collections Source: https://docs.okrapdf.com/cli/collections Query across a collection of documents from the CLI. A **collection** groups documents so you can ask one question across all of them. From the CLI you **list** collections and **query** them. Collections themselves are created and managed in the [web app](/web/overview) or via the [Collections API](/api-reference/collections/create-collection) — there is no `okra collections create`. ## Commands ```bash theme={null} okra collections list # list your collections okra collections query "" # ask one question across the collection ``` `collections` accepts either a **collection name** or a **collection ID** (`col-...`). The CLI tries ID lookup first, then falls back to name. ## List collections ```bash theme={null} okra collections list okra collections list --json ``` ## Query a collection `okra collections query` fans the same question out across every document in the collection and returns the combined result. ```bash theme={null} okra collections query earnings "What changed quarter over quarter?" # Write the result to a file (CSV / JSON inferred from extension) okra collections query earnings "What changed quarter over quarter?" -o earnings.csv ``` | Flag | Description | | ----------------- | -------------------------------------------------------------------- | | `--schema ` | **Experimental.** JSON Schema file for structured fan-out extraction | ```bash theme={null} # Experimental structured fan-out okra collections query earnings "Extract revenue and net income" --schema ./schema.json ``` ## Creating and publishing collections Creating a collection, adding or removing documents, and publishing a collection to a public URL are not CLI operations: * **Create / manage** — use the [web app](/web/overview) or `POST /v1/collections` (see [Create a collection](/api-reference/collections/create-collection)). * **Publish** — publishing to a public URL asserts that you own or are licensed to publish the content, so it is a deliberate, gated action in the web app, not a one-line CLI flag. Public collection pages live at `okrapdf.com/c/`. They are part of the free, read-only public tier — see the [web overview](/web/overview) for how the surfaces relate. # Extract Source: https://docs.okrapdf.com/cli/extract Upload a PDF and extract structured data in one command. `okra extract` uploads, processes, and extracts structured data from a PDF in one step. The source can be a **local file path**, a **URL**, or the **document ID** of a PDF you already uploaded. ```bash theme={null} # From a local file okra extract ./report.pdf # From a URL okra extract https://example.com/report.pdf # From an existing document okra extract doc-abc123 ``` ## Structured extraction with a schema Pass a JSON Schema to get structured JSON back. The schema can be a file path or inline JSON. ```bash theme={null} okra extract ./invoice.pdf \ --schema ./invoice.schema.json \ --prompt "Extract vendor, total, currency, and due date" ``` When stdout is not a TTY (or with `--json`), the result comes back in the standard envelope: ```json theme={null} { "ok": true, "command": "extract", "result": { "data": {} }, "cost": { "usd": null }, "citations": [], "next_actions": [] } ``` ## Per-field citations (`--cite`) Add `--cite` to attach **per-field source citations** — the page and bounding box each extracted value came from. Grounding is opt-in: without `--cite` you get values only. ```bash theme={null} okra extract ./invoice.pdf --schema ./invoice.schema.json --cite ``` Citations are returned in the Anthropic-shaped `citations` array (`type: page_location`, with the source page, bbox, and the schema field each value maps to), alongside the extracted `data`. ## Fire-and-forget (`--no-wait`) By default `okra extract` waits for processing to finish. Use `--no-wait` to queue the work and return immediately; follow up with `okra jobs wait`. ```bash theme={null} okra extract ./report.pdf --no-wait okra jobs wait ``` ## Flags | Flag | Description | | ------------------ | ------------------------------------------------------------------------ | | `--schema ` | JSON Schema file or inline JSON for structured extraction | | `--prompt ` | Extraction prompt (default: "Extract all data according to the schema") | | `--cite` | Return per-field source citations (page + bbox) for each extracted value | | `--no-wait` | Fire-and-forget — queue the job and don't wait for processing | Global flags (`--json`, `--quiet`, `--output`) apply as well — see the [CLI Reference](/cli/reference). To browse a document's text, tables, and structure after extraction, use the grounded [`context`](/cli/reference) commands (`okra context structure`, `okra context tables`, `okra context get`) or read raw markdown with `okra read `. # Jobs Source: https://docs.okrapdf.com/cli/jobs Inspect, wait on, and control parse, render, and workflow jobs. `okra jobs` inspects the parse, render, and workflow jobs your other commands create. Jobs are created implicitly — `okra upload`, `okra extract`, `okra parse`, `okra render`, and the workflow commands all enqueue a job — so the `jobs` surface is for **listing, waiting, and controlling** them, not creating them. ## Recommended flow ```bash theme={null} # 1) Kick off work that enqueues a job (e.g. a fire-and-forget parse) okra upload ./report.pdf --no-wait # 2) Wait for the latest parse job for that document okra jobs wait --timeout 600 # 3) Inspect the job and its result okra jobs get ``` `okra jobs wait` accepts **either** a job ID **or** a document ID. Given a document ID, it waits for that document's latest `document.parse` job. ## Commands ```bash theme={null} okra jobs list # list your jobs (newest first) okra jobs list --status completed # filter by status okra jobs list --type document.parse # filter by job type okra jobs list --doc # filter by document okra jobs get # job status + result (alias: show) okra jobs wait # block until a job finishes okra jobs events # print the job event-stream URL okra jobs cancel # cancel a queued or running job okra jobs retry # retry a failed job okra jobs resume # resume a paused job ``` ### `jobs list` flags | Flag | Description | | ------------------- | ------------------------------------------------------------- | | `--limit ` | Max jobs to return | | `--type ` | Filter by job type (e.g. `document.parse`, `document.render`) | | `--status ` | Filter by job status | | `--doc ` | Filter to jobs for one document | Combine with the global `--json` flag for machine-readable output: ```bash theme={null} okra jobs list --status completed --limit 5 --json ``` When stdout is not a TTY, `okra jobs` commands emit the standard envelope. For example, `okra jobs list --json` returns: ```json theme={null} { "ok": true, "command": "jobs list", "result": { "jobs": [] }, "cost": { "usd": null }, "citations": [], "next_actions": [] } ``` ### `jobs wait` ```bash theme={null} okra jobs wait okra jobs wait # waits for the latest document.parse job okra jobs wait --timeout 600 ``` | Flag | Description | | --------------------- | ---------------------------------------- | | `--timeout ` | Maximum seconds to wait (default: `300`) | ### `jobs cancel`, `retry`, and `resume` ```bash theme={null} okra jobs cancel # cancel a queued or running job okra jobs retry # retry a failed job okra jobs resume # resume a paused job ``` Only non-terminal jobs can be cancelled; only failed jobs can be retried; only paused jobs can be resumed. To create work, use a verb command (`okra upload`, `okra extract`, `okra parse`, `okra render`) rather than `okra jobs`. Those commands enqueue the job and, by default, wait for it — add `--no-wait` to queue and follow up with `okra jobs wait`. # Quickstart Source: https://docs.okrapdf.com/cli/quickstart Install the Okra CLI and work with PDFs from your terminal. ## Install ```bash theme={null} npm install -g @okrapdf/cli ``` The package installs the `okra` binary. For one-off usage: ```bash theme={null} npx @okrapdf/cli --help ``` ## Authenticate ```bash theme={null} export OKRA_API_KEY=okra_sk_YOUR_KEY okra auth set-key "$OKRA_API_KEY" okra auth status ``` ## Upload a PDF ```bash theme={null} okra upload ./report.pdf okra upload https://example.com/report.pdf ``` ## Ask a question ```bash theme={null} okra chat "What is total revenue?" --doc doc-abc123 ``` ## Extract structured data ```bash theme={null} okra extract ./invoice.pdf \ --schema ./invoice.schema.json \ --prompt "Extract vendor, total, currency, and due date" ``` ## Read markdown ```bash theme={null} okra read doc-abc123 --pages 1-3 ``` ## Machine and agent output When stdout is not a TTY, most `okra` commands automatically emit a structured JSON envelope. You can also force this in an interactive terminal with `--json`: ```bash theme={null} okra context resolve "https://example.com/report.pdf" --json okra extract ./invoice.pdf --schema ./schema.json --json ``` The envelope returns a uniform success/failure shape with `ok`, `result`, `cost`, `citations`, and `next_actions`. See the [CLI Reference](/cli/reference) for the full envelope contract, stable error codes, and agent stop-gate rules. ## What's next Structured extraction flags and examples. Ask questions against a processed document. Query across multiple documents. Auth, environment variables, and global flags. # Reference Source: https://docs.okrapdf.com/cli/reference Current auth, environment variables, and global CLI options. ## Envelope format When stdout is not a TTY (and always with `--json`), every command emits a structured JSON envelope that unifies success and failure: ```json theme={null} { "ok": true, "command": "context resolve", "result": {}, "cost": { "usd": null }, "citations": [], "next_actions": [] } ``` On failure, the same top-level shape is used with `"ok": false` and additional fields: ```json theme={null} { "ok": false, "command": "collections publish", "error": "confirmation_required", "message": "Public publish asserts that you own or are licensed to publish this content.", "cost": { "usd": null }, "citations": [], "next_actions": [ { "cmd": "okra collections publish earnings --confirm-rights", "why": "Confirm the public publish rights gate explicitly." } ] } ``` ### Field reference | Field | Description | | -------------- | ------------------------------------------------------------------------------ | | `ok` | `true` on success, `false` on failure. | | `command` | The command name as executed (e.g. `context resolve`). | | `result` | Command-specific payload on success. | | `error` | Stable, **machine-readable** error code on failure (never a freeform message). | | `message` | Human-readable explanation of the failure. | | `cost` | Estimated cost, when available (`usd` field). | | `citations` | Any source citations returned by the command. | | `next_actions` | Suggested follow-up commands that an agent can run directly. | ### Error codes and exit codes * `error` is always a stable machine code (e.g. `confirmation_required`, `human_review_required`, `engine_not_available`). Freeform messages go in `message`, not `error`. * Commands that fail with `"ok": false` return a **non-zero** exit code. * When a command succeeds, the exit code is zero. ### Agent stop-gates Agents must **stop** when `error` is either `confirmation_required` or `human_review_required`, show the `message` to a human, and only rerun a `next_actions[].cmd` after explicit approval. Do not add confirmation flags (e.g. `--confirm-rights`, `--yes`, `--attest`) without human input. ### Enabling JSON output ```bash theme={null} # Automatic when stdout is not a TTY okra context resolve "https://example.com/report.pdf" | jq . # Force JSON in an interactive terminal okra upload ./report.pdf --json okra upload ./report.pdf -o json ``` ## Global options ```text theme={null} okra --help okra --version okra --json okra --quiet okra --output result.json ``` | Flag | Description | | ----------------- | -------------------------------------------- | | `--json` | Emit machine-readable JSON where supported. | | `--quiet` | Suppress progress and human-readable output. | | `--output ` | Write output to a file instead of stdout. | | `--version` | Print the installed package version. | ## Auth ```bash theme={null} okra auth login okra auth set-key okra_sk_YOUR_KEY okra auth status okra auth whoami okra auth token okra auth logout ``` ## Primary commands ```bash theme={null} okra upload ./report.pdf okra extract ./invoice.pdf --schema ./schema.json okra chat "Summarize this document" --doc doc-abc123 okra read doc-abc123 --pages 1-5 okra list okra delete doc-abc123 okra collection query earnings "What changed quarter over quarter?" ``` ## Noun-first agent surface The agent contract uses stable resource nouns that match API resources and the `/v1/resources` catalog. Legacy ergonomic verbs (e.g. `upload`, `read`, `chat`, `extract`, `parse`, `audit`, `redact`, `render`) remain compatible, but the preferred agent surface is: * `resources` * `documents` * `files` * `jobs` * `agents` * `workflows` * `collections` Run `okra resources list` to discover every API noun and verb, and `okra --help` for a resource's subcommands. ## Grounded context commands Before (or instead of) a full parse, the `context` commands navigate a source and retrieve bounded, cited context: ```bash theme={null} okra context structure doc-abc123 # navigable sections, page ranges, artifacts okra context tables doc-abc123 # detected tables with columns + page hints okra context get "termination clause" --source-id doc-abc123 okra context ask "What is the guaranteed fee?" --source-id doc-abc123 ``` ## Environment variables | Variable | Description | | --------------- | -------------------------------------------------- | | `OKRA_API_KEY` | API key used by authenticated commands. | | `OKRA_BASE_URL` | API origin. Defaults to `https://api.okrapdf.com`. | | `OKRA_QUIET` | Set to `1` for quiet mode. | # Verify Source: https://docs.okrapdf.com/cli/verify Verify a claim against a document page with bbox-grounded evidence. ## Overview `okra documents verify` checks a **specific claim** against a **specific page** of a document and returns a grounded verdict with visual evidence. It answers "is this claim supported by what's actually on the page?" — not a page-level approval workflow. ```bash theme={null} okra documents verify "" --page ``` The vision model reads the page and returns one of three verdicts: * **`supported`** — the page supports the claim * **`contradicted`** — the page contradicts the claim * **`not_visible`** — the claim can't be confirmed from what's on the page ## Verify a claim ```bash theme={null} okra documents verify doc-abc123 "Total revenue was $4.2M in FY2023" --page 2 ``` ```json theme={null} { "ok": true, "command": "documents verify", "result": { "verdict": "supported", "page": 2, "bbox": { "x": 0.12, "y": 0.34, "w": 0.4, "h": 0.05 }, "evidence_snippet": "Total revenue for the fiscal year ended 2023 was $4.2M.", "page_image_url": "https://res.okrapdf.com/v1/documents/doc-abc123/pg_2.png", "confidence": 0.96, "model": "gemini-3-flash" }, "cost": { "usd": null }, "citations": [], "next_actions": [] } ``` Every result carries the **page**, an `evidence_snippet` of the supporting (or contradicting) text, a `page_image_url` for visual reference, a `confidence` score, and the resolved `bbox` of the evidence on the page. ## Focus on a region (`--bbox`) Pass `--bbox` to constrain verification to a region of the page instead of the whole page. Coordinates are normalized `{ "x", "y", "w", "h" }`. ```bash theme={null} okra documents verify doc-abc123 "The signature is dated March 3" \ --page 7 \ --bbox '{"x":0.1,"y":0.8,"w":0.3,"h":0.1}' ``` ## Arguments and flags | Argument / Flag | Description | | --------------- | ----------------------------------------------------------- | | `` | Document ID (or 6-char short hash) to verify against | | `` | The claim to check, as a quoted string | | `--page ` | Page number (1-based) to verify against (**required**) | | `--bbox ` | Optional region `{"x":..,"y":..,"w":..,"h":..}` to focus on | ## Pipe-friendly use `okra documents verify` emits the standard envelope, so a verdict is easy to branch on in a script: ```bash theme={null} verdict=$(okra documents verify doc-abc123 "Revenue grew YoY" --page 2 --json \ | jq -r '.result.verdict') [ "$verdict" = "supported" ] && echo "claim holds" ``` This is the document-level claim check. To verify a PDF-backed claim from an agent (with `document_id` or a public `pdf_url`), use the `verify_source` tool over [MCP](/mcp/overview). # React Hooks Source: https://docs.okrapdf.com/developers/react React helpers from the @okrapdf/sdk/react subpath. ## Install ```bash theme={null} npm install @okrapdf/sdk ``` `@okrapdf/sdk/react` is a subpath export of the SDK package, not a separate npm package. ## OkraProvider Wrap a subtree with `OkraProvider` and provide either a `documentId`, a `url`, or a `file`. ```tsx theme={null} 'use client'; import { OkraProvider } from '@okrapdf/sdk/react'; export function DocumentRoot({ documentId, children }) { return ( {children} ); } ``` Use publishable browser keys or a server-side boundary for browser apps. Do not expose `okra_sk_` secret keys in client-side bundles. ## Status and pages ```tsx theme={null} import { useOkraDocument, useDocumentStatus, usePages } from '@okrapdf/sdk/react'; function DocumentPanel() { const { session, documentId, isReady } = useOkraDocument(); const status = useDocumentStatus(session); const pages = usePages(session, { enabled: isReady }); if (status.error) return

{status.error.message}

; if (!documentId) return

Resolving document...

; return (

{status.data?.phase ?? 'loading'}

{pages.data.map((page) => (

Page {page.pageNumber ?? page.page}

{page.markdown ?? page.content}
))}
); } ``` ## Chat ```tsx theme={null} import { useChat, useOkraDocument } from '@okrapdf/sdk/react'; function ChatPanel() { const { session } = useOkraDocument(); const chat = useChat({ session, stream: true }); return (
{chat.messages.map((message) => (

{message.role}: {message.content}

))}
); } ``` ## Structured extraction The React package does not ship a separate `useStructuredOutput` hook. Call `session.prompt(...)` with a schema from your component or wrap it in your app's own state hook. ```tsx theme={null} import { useState } from 'react'; import { z } from 'zod'; import { useOkraDocument } from '@okrapdf/sdk/react'; const Invoice = z.object({ vendor: z.string(), total: z.number(), }); function InvoiceFields() { const { session } = useOkraDocument(); const [data, setData] = useState | null>(null); async function extract() { if (!session) return; const result = await session.prompt('Extract invoice fields', { schema: Invoice, }); setData(result.data ?? null); } return (
{data ?
{JSON.stringify(data, null, 2)}
: null}
); } ``` ## DocumentAgent realtime context For realtime DocumentAgent state and methods, use `createOkraContext(...)`. This requires the `agents` React package in your app. ```tsx theme={null} import { createOkraContext } from '@okrapdf/sdk/react'; const okra = createOkraContext({ host: 'https://api.okrapdf.com', agent: 'DocumentAgent', authEndpoint: '/api/okra/document-token', }); export function LiveDocument({ documentId }) { const document = okra.useDocument(documentId); const phase = okra.useDocumentSlice(documentId, (state) => state.phase); return

{phase ?? document.state?.phase ?? 'connecting'}

; } ``` # TypeScript SDK Source: https://docs.okrapdf.com/developers/sdk Use @okrapdf/sdk for document sessions, files, collections, and workflows. ## Install ```bash theme={null} npm install @okrapdf/sdk ``` ```ts theme={null} import { createOkra, OkraClient } from '@okrapdf/sdk'; import { doc } from '@okrapdf/sdk/doc'; ``` `createOkra(...)` returns an `OkraClient`. Use it when you want workflow defaults or middleware-style options. Use `new OkraClient(...)` when you want the direct class. ## Upload and ask ```ts theme={null} import { createOkra } from '@okrapdf/sdk'; const okra = createOkra({ apiKey: process.env.OKRA_API_KEY }); const session = await okra.sessions.create('./report.pdf', { wait: true, model: 'anthropic/claude-haiku-4.5', }); const { answer, sources } = await session.prompt('What is total revenue?'); console.log(answer); console.log(sources); ``` `sessions.create(...)` accepts local file paths in Node, URLs, `Blob`, `ArrayBuffer`, or `Uint8Array`. Use `sessions.from(documentId)` to attach to an existing document. ## Read pages and entities ```ts theme={null} const status = await session.status(); const pages = await session.pages({ range: '1-3' }); const tables = await session.entities({ type: 'table' }); console.log(status.phase, pages.length, tables.nodes.length); ``` ## Structured output ```ts theme={null} import { z } from 'zod'; const Invoice = z.object({ vendor: z.string(), total: z.number(), currency: z.string().optional(), }); const result = await session.prompt('Extract invoice fields', { schema: Invoice, }); console.log(result.data); ``` ## Streaming ```ts theme={null} for await (const event of session.stream('Summarize in 3 bullets')) { if (event.type === 'text_delta') process.stdout.write(event.text); if (event.type === 'done') console.log('\nfinal:', event.answer); } ``` ## Passive file assets Use `files.upload(...)` when you want to store a PDF first and decide later whether to parse, host, or run a workflow. ```ts theme={null} const file = await okra.files.upload('./invoice.pdf'); console.log(file.id); console.log(file.urls.bytes); ``` ## Host and URL building The SDK exports a deterministic URL builder for document-derived assets: ```ts theme={null} const d = doc(session.id, { fileName: 'report.pdf' }); console.log(d.pg[1].png()); console.log(d.pg[1].md()); console.log(d.full.md()); ``` For clean hosted PDF deployments, call the REST [Host API](/api-reference/host/create-hosted-pdf) or upload through `files.upload(...)` and publish with `/v1/host`. ## Invoice extraction workflow ```ts theme={null} const file = await okra.files.upload('./invoice.pdf'); const run = await okra.runInvoiceExtraction({ inputs: [file.id], quality: 'standard', }); console.log(run.runId, run.exports.csvUrl, run.exports.jsonUrl); ``` ## Dynamic agent workflows The stable SDK surface currently exposes built-in workflows such as invoice extraction. Custom workflow authoring lives in the MCP and REST workflow surfaces: * Use [MCP](/mcp/overview) when an agent should draft, run, and inspect a workflow. * Use `POST /v1/workflows` and `POST /v1/runs` when your app wants to create and run a workflow directly. ## Collections ```ts theme={null} const stream = okra.collections.query( 'col-abc123', 'Extract revenue, net income, and EPS.', ); for await (const event of stream) { console.log(event); } ``` ## API surface ```ts theme={null} createOkra({ apiKey, baseUrl?, sharedSecret?, fetch?, workflow? }) => OkraClient okra.sessions.create(sourceOrDocId, { wait?, model?, upload?, waitOptions? }) => session okra.sessions.from(documentId, { model? }) => session okra.files.upload(input, options?) okra.files.get(fileId) okra.files.list(options?) okra.files.delete(fileId) session.status() session.wait() session.pages({ range? }) session.page(pageNumber) session.entities({ type?, limit?, offset? }) session.prompt(query, { schema?, model? }) session.stream(query, options?) session.publish() session.shareLink({ role, expiresInMs, maxViews, label }) ``` # FAQ Source: https://docs.okrapdf.com/faq Common questions about okraPDF ## Getting Started New accounts start with \*\*$5 free credit** (~250 pages at $0.02/page). No credit card required. After you've used your free credit, you can add more from Settings. okraPDF supports: * **PDF files** — native PDFs and scanned documents * **Images** — PNG, JPG, JPEG (converted to single-page PDF) We don't currently support Word docs, Excel files, or PowerPoint. Export those as PDF first. Yes: * **Maximum file size:** 100 MB * **Maximum pages:** 500 pages per document For larger documents, consider splitting into smaller files. Most documents process in **10-30 seconds**. Factors that affect speed: * Page count — more pages take longer * Scan quality — low-quality scans need more OCR processing * Table complexity — dense tables require more analysis ## Extraction Quality okraPDF uses Google Document AI, which achieves **95%+ accuracy** on clean documents. Accuracy depends on: * **Document quality** — 300 DPI scans work best * **Text clarity** — handwriting is less accurate than typed text * **Language** — English has the highest accuracy Use the Review feature: 1. Click any extracted table or figure 2. Compare side-by-side with the original 3. Click to edit — AI suggests corrections 4. Approve changes The AI only corrects based on what's in the original image. It won't add or invent data. Yes. okraPDF handles both native PDFs (with embedded text) and scanned images. For best results with scans: * Use 300 DPI or higher resolution * Ensure pages are straight (not skewed) * Avoid shadows or dark edges Handwriting recognition is supported but less accurate than printed text. Complex or cursive handwriting may have lower confidence scores. Always verify handwritten content in the Review view. ## Tables and Figures okraPDF detects: * Standard grid tables with borders * Borderless tables (aligned by whitespace) * Multi-level headers * Merged cells * Tables spanning multiple pages Figures include: * Charts and graphs (bar, line, pie, etc.) * Diagrams and flowcharts * Photos and illustrations * Logos and signatures * Infographics Yes. When we detect a figure, we also look for nearby captions (like "Figure 1: Revenue Growth") and link them together in the extraction. ## Exporting Data * **CSV** — Opens in Excel, Google Sheets, any spreadsheet app * **JSON** — Structured data for developers * **Markdown** — For documentation and notes * **Clipboard** — Paste directly into spreadsheets Currently, you export tables one at a time. We're working on batch export features. Yes. We preserve: * Table headers and column structure * Row order and cell alignment * Merged cell boundaries * Page location reference ## Privacy and Security Documents are stored in Google Cloud Storage with: * Encryption at rest (AES-256) * Encryption in transit (TLS 1.3) * Data centers in the United States **No.** Your documents are never used to train AI models. We use Google Document AI and other services that process your data but don't retain it for training. Yes. Delete any document from your library at any time. Deleted documents are removed from our storage within 24 hours. Only you. Documents are isolated per account. We don't share your data with other users or third parties (except our infrastructure providers listed in our privacy policy). ## Account and Billing okraPDF uses a prepaid credit system: * Add credits from Settings (min \$5, no processing fee) * OCR costs \$0.02 per page * Chat costs the actual API cost (typically \$0.01-0.05/message) * Credits never expire * Failed uploads are automatically refunded You can still view and export previously processed documents. To process new documents or chat, add credits from Settings. Failed document processing is automatically refunded. For other refund requests, email [support@okrapdf.com](mailto:support@okrapdf.com). ## Troubleshooting Try these steps: 1. Refresh the page 2. Check your internet connection 3. Try a smaller file (under 50 MB) 4. Clear browser cache and retry If still stuck, email [support@okrapdf.com](mailto:support@okrapdf.com) with your document details. Some tables may not be detected if: * The table lacks clear structure (no borders, inconsistent spacing) * It's actually a formatted list, not a table * The scan quality is too low Try uploading at higher resolution or with a cleaner scan. 1. Ensure pop-ups aren't blocked 2. Try a different browser 3. Use "Copy to Clipboard" as an alternative 4. Check if your browser has sufficient permissions ## Still have questions? Email us at [support@okrapdf.com](mailto:support@okrapdf.com) — we typically respond within 24 hours. # Chat Widget Source: https://docs.okrapdf.com/integrations/chat-widget Embed a PDF chatbot on any website with one script tag ## Overview Add a floating chat bubble to any website that answers questions about your PDF. One script tag, zero dependencies, streaming responses. Try the embedded chat widget on a live page ## Quick Start Upload a document, then paste this before ``: ```html theme={null} ``` That's it. A chat bubble appears in the bottom-right corner. Your visitors ask questions, the widget streams answers from your PDF. ```bash theme={null} okra upload earnings.pdf # → Document ID: ocr-abc123 ``` Create a key scoped for client-side use in your [dashboard](https://app.okrapdf.com/dashboard). Publishable keys (prefixed `okra_pk_`) can only read — they can't upload or delete documents. ```html theme={null} ``` ## How It Works The widget calls okraPDF's OpenAI-compatible completions endpoint directly from the browser: ``` Browser → POST /v1/documents/{id}/chat/completions → Streaming SSE response ``` No backend proxy needed. The publishable key restricts access to read-only completions on that specific document. ## Use with Chatbot Builders Since the completions API is OpenAI-compatible, any chatbot platform that supports custom endpoints works out of the box. Add an **HTTP Request** block: * **URL:** `https://api.okrapdf.com/v1/documents/YOUR_DOC_ID/chat/completions` * **Method:** POST * **Headers:** `Authorization: Bearer YOUR_OKRA_KEY` * **Body:** `{"model":"moonshotai/kimi-k2.5","messages":[{"role":"user","content":"{{userQuestion}}"}]}` * **Response mapping:** `choices[0].message.content` → your response variable * **Timeout:** Set to 120s (LLM calls take 5-30s) Any platform with a "Custom OpenAI" or "HTTP Request" integration: * **Base URL:** `https://api.okrapdf.com/v1/documents/YOUR_DOC_ID` * **API Key:** Your okraPDF key (passed as OpenAI API key) * **Model:** `moonshotai/kimi-k2.5` ```python theme={null} from openai import OpenAI client = OpenAI( base_url="https://api.okrapdf.com/v1/documents/YOUR_DOC_ID", api_key="okra_pk_your_key_here", ) response = client.chat.completions.create( model="moonshotai/kimi-k2.5", messages=[{"role": "user", "content": "What was total revenue?"}], ) print(response.choices[0].message.content) ``` Use the [okraPDF n8n node](https://github.com/okrapdf/n8n-nodes-okrapdf) for native integration. ## Customization The widget accepts these `data-` attributes: | Attribute | Description | Default | | ---------- | ------------------------------ | ------- | | `data-doc` | Document ID (required) | — | | `data-key` | Publishable API key (required) | — | For deeper customization (colors, position, greeting), fork the [widget source](https://github.com/okrapdf/examples/tree/main/chatpdf-widget) — it's \~80 lines of vanilla JS. ## Source Code Vanilla JS, zero dependencies, \~80 lines Deployed example with streaming chat # Chrome Extension Source: https://docs.okrapdf.com/integrations/chrome-extension Capture and process PDFs directly from your browser ## Overview See a PDF in your browser? Capture it with one click. The okraPDF Chrome Extension sends documents directly to your library for instant processing.