SDK Methods
Complete reference for the DocuDevs Python SDK (docudevs-sdk).
Client Initialization
DocuDevsClient
Initialize the client with your API key.
from docudevs.docudevs_client import DocuDevsClient
import os
client = DocuDevsClient(
api_url="https://api.docudevs.ai", # Optional, defaults to production
token=os.getenv("DOCUDEVS_API_KEY") # Required
)
Schema Helpers
Convenience functions for building JSON Schema strings from Pydantic models or dicts.
json_schema
Convert a Pydantic model or dict to a JSON Schema string. Use for single-object extraction.
from docudevs import json_schema
from pydantic import BaseModel, Field
class Invoice(BaseModel):
number: str = Field(description="Invoice number")
total: float
# From a Pydantic model
schema = json_schema(Invoice)
# From a dict
schema = json_schema({"type": "object", "properties": {"name": {"type": "string"}}})
array_schema
Wrap a Pydantic model or dict as an array schema. Use for map-reduce extraction where each chunk produces multiple items.
from docudevs import array_schema
from pydantic import BaseModel
class LineItem(BaseModel):
sku: str
description: str
quantity: int
# Produces {"type": "array", "items": <LineItem schema>}
schema = array_schema(LineItem)
# From a dict
schema = array_schema({"type": "object", "properties": {"sku": {"type": "string"}}})
Both helpers accept:
- Pydantic model classes — calls
model_json_schema()automatically - Dicts — used as-is
Document Processing
submit_and_process_document
Upload and process a document for structured data extraction. Use extract_figures=True to store figure images and metadata. For fillable PDFs, acro_form_metadata=True stores AcroForm metadata as a separate job artifact that you can fetch later with get_acroform_metadata(...).
job_guid = await client.submit_and_process_document(
document=document_bytes,
document_mime_type="application/pdf",
prompt="Extract invoice data",
schema={...}, # Optional JSON schema
ocr="PREMIUM", # Optional: DEFAULT, PREMIUM, LOW
llm="HIGH", # Optional: DEFAULT, MINI, HIGH
extract_figures=True,
acro_form_metadata=True,
source_locations=True,
source_location_granularity="block",
)
submit_and_process_document_with_configuration
Process a document using a saved configuration.
job_guid = await client.submit_and_process_document_with_configuration(
document=document_bytes,
document_mime_type="application/pdf",
configuration_name="invoice-config"
)
submit_and_ocr_document
Process a document with OCR only (no structured extraction). Use extract_figures=True to store figure images and metadata.
job_guid = await client.submit_and_ocr_document(
document=document_bytes,
document_mime_type="application/pdf",
ocr="PREMIUM",
ocr_format="markdown", # markdown, plain, jsonl (for Excel)
describe_figures=True,
extract_figures=True
)
analyze_document
Analyze document structure and return a job GUID.
job_guid = await client.analyze_document(
document=document_bytes,
document_mime_type="application/pdf",
ocr="PREMIUM"
)
wait_until_ready
Wait for a job to complete and retrieve the result.
result = await client.wait_until_ready(
guid=job_guid,
timeout=180,
poll_interval=5.0,
result_format="json" # json, csv, excel, or None (legacy object)
)
Low-Level Document Processing
These primitives back the submit_and_* convenience helpers above. Use them directly when you need to separate upload from processing, or drive a custom flow.
upload_document
Upload a single document and return the raw response (parsed.guid on success).
response = await client.upload_document(body=UploadDocumentBody(document=file_obj))
guid = response.parsed.guid
upload_files
Upload multiple files in one request.
response = await client.upload_files(body=UploadFilesBody(...))
process_document
Process an already-uploaded document.
await client.process_document(guid, body=upload_command, depends_on=None)
depends_on is an optional parent job GUID; when set, the scheduler waits for the parent job before dispatching this one.
process_document_with_configuration
Process an already-uploaded document using a named configuration.
await client.process_document_with_configuration(guid, configuration="invoice-config")
ocr_document
Process an already-uploaded document with OCR-only mode.
await client.ocr_document(guid, body=ocr_command, ocr_format="markdown")
generate_schema
Generate a JSON schema from a sample document using AI. Returns a job GUID whose result (via wait_until_ready or result_json) is the generated schema as a JSON string.
job_guid = await client.generate_schema(
document=sample_bytes,
document_mime_type="application/pdf",
instructions="Extract invoice header fields",
)
analyze_document_and_wait
Analyze document structure and wait for the result in one call (combines analyze_document and wait_until_ready).
result = await client.analyze_document_and_wait(
document=document_bytes,
document_mime_type="application/pdf",
ocr="PREMIUM",
timeout=180,
)
Job Results and Status
status
Get raw job status.
response = await client.status(guid)
result
Get the raw (legacy) job result response.
response = await client.result(guid)
result_json
Get a job result explicitly as JSON via /job/result/{uuid}/json. Falls back to the legacy result endpoint on a 404 (older server) or 415 (non-JSON result).
data = await client.result_json(guid)
result_csv
Get a job result as CSV text via /job/result/{uuid}/csv. Raises if the result is not JSON-backed (415).
csv_text = await client.result_csv(guid)
result_excel
Get a job result as XLSX bytes via /job/result/{uuid}/excel. Pass configuration to inject the result into a configuration's uploaded Excel template.
xlsx_bytes = await client.result_excel(guid, save_to="result.xlsx", configuration="invoice-config")
get_source_locations
Get resolved source locations for a structured-result job (requires source_locations=True at submission).
locations = await client.get_source_locations(guid)
wait_until_ready_with_source_locations
Wait for completion, then return both the JSON result and the source-location artifact as a StructuredResultWithSources(result=..., source_locations=...).
bundle = await client.wait_until_ready_with_source_locations(guid, timeout=180)
print(bundle.result, bundle.source_locations)
submit_and_wait_for_document_with_source_locations
Convenience helper: submit a document with source_locations=True, then wait and return both the result and source-location artifact.
bundle = await client.submit_and_wait_for_document_with_source_locations(
document=document_bytes,
document_mime_type="application/pdf",
prompt="Extract invoice data",
)
Workbook
Workbook artifacts are published by WORKBOOK extraction-mode jobs (single XLSX input, no target schema). See Workbook Normalization for the extraction-mode contract.
get_workbook_plan
Fetch the caller-inspectable transformation plan for a workbook result.
plan = await client.get_workbook_plan(guid)
get_workbook_source_map
Fetch the caller-inspectable source map for a workbook result.
source_map = await client.get_workbook_source_map(guid)
get_workbook_summary
Fetch the published summary artifact for a workbook result.
summary = await client.get_workbook_summary(guid)
Client Pipelines
Client pipelines run a hybrid graph: remote DocuDevs segments interleaved with local Python callables that execute in your own process. See Client Pipelines for the execution model and constraints.
run_client_pipeline
Run a hybrid client pipeline end to end: uploads the document, then executes the graph, calling back into local functions between remote segments. Not resumable — if the process stops, a later attempt runs the graph from the beginning.
result = await client.run_client_pipeline(
document=document_bytes,
document_mime_type="application/pdf",
pipeline=my_hybrid_pipeline,
timeout=900.0,
poll_interval=2.0,
on_event=None,
)
Pipeline Processing
Pipeline mode uploads one document, runs one shared OCR pass, and executes a graph of nodes. Use the SDK builder so dependencies, source paths, and final outputs refer to previous nodes directly.
process_pipeline_document
Upload and process a document with a pipeline builder definition.
from docudevs import P, Pipeline
pipeline = Pipeline().ocr(mode="AUTO")
extract_data = pipeline.extract(
"extract_data",
source=P.ocr.content,
prompt="Extract the requested fields.",
schema={
"type": "object",
"properties": {"name": {"type": "string"}},
},
)
pipeline.final(
"final_result",
depends_on=[extract_data],
output=extract_data.result,
)
job_guid = await client.process_pipeline_document(
document=document_bytes,
document_mime_type="application/pdf",
pipeline=pipeline,
ocr="AUTO",
trace=True
)
result = await client.wait_until_ready(job_guid, result_format="json")
nodes = await client.get_pipeline_nodes(job_guid)
process_uploaded_pipeline_document
Run pipeline processing on a document that was already uploaded.
await client.process_uploaded_pipeline_document(
guid=uploaded_guid,
pipeline=pipeline,
mime_type="application/pdf",
ocr="AUTO"
)
save_pipeline_configuration and get_pipeline_configuration
Save and retrieve named pipeline configurations.
await client.save_pipeline_configuration(
"router-pipeline",
pipeline=pipeline,
mime_type="application/pdf",
ocr="AUTO"
)
saved_pipeline = await client.get_pipeline_configuration("router-pipeline")
get_pipeline_nodes
Read node-level runtime status from a pipeline job.
nodes = await client.get_pipeline_nodes(job_guid)
for node in nodes:
print(node["id"], node["status"])
For the full pipeline JSON contract, node types, and branching examples, see Pipeline Mode.
build_upload_command_pipeline
Build the raw UploadCommand for pipeline extraction without submitting it. Used internally by process_pipeline_document and process_uploaded_pipeline_document; call it directly when you need the command object itself (for example to save it as a configuration with save_pipeline_configuration).
command = client.build_upload_command_pipeline(
pipeline=pipeline,
mime_type="application/pdf",
ocr="AUTO",
)
Batch Processing
submit_and_process_batch
Upload and process multiple documents as a batch.
batch_guid = await client.submit_and_process_batch(
documents=[file1_bytes, file2_bytes],
document_mime_type="application/pdf",
prompt="Extract data",
max_concurrency=5
)
submit_and_process_batch_with_configuration
Upload and process multiple documents as a batch using a saved configuration.
batch_guid = await client.submit_and_process_batch_with_configuration(
documents=[file1_bytes, file2_bytes],
document_mime_type="application/pdf",
configuration_name="invoice-config",
max_concurrency=5,
)
Low-Level Batch Processing
These primitives back the submit_and_process_batch* convenience helpers above.
create_batch
Create a new batch job and return its GUID.
batch_guid = await client.create_batch(max_concurrency=5)
upload_batch_document
Upload a single document into an existing batch.
info = await client.upload_batch_document(batch_guid, document_bytes, "application/pdf", file_name="invoice.pdf")
process_batch
Finalize and start processing a batch that has already had documents uploaded.
await client.process_batch(
batch_guid,
prompt="Extract data",
schema="",
mime_type="application/pdf",
)
process_batch_with_configuration
Finalize and start processing a batch using a saved configuration.
await client.process_batch_with_configuration(batch_guid, "invoice-config")
schedule_batch
Call the concurrency-aware scheduling endpoint for a batch explicitly.
await client.schedule_batch(batch_guid)
Lookup Files
Lookup files are reference data (for example a product catalog or vendor list) attached to a configuration or a single batch so extraction prompts can resolve against it. See Lookup Files for the extraction-time behavior.
upload_configuration_lookup_file
Attach a lookup file to a named configuration. Applies to every job that uses the configuration until replaced or deleted.
await client.upload_configuration_lookup_file("invoice-config", file_bytes, file_name="vendors.csv")
get_configuration_lookup_file
Download the lookup file attached to a configuration.
data = await client.get_configuration_lookup_file("invoice-config")
delete_configuration_lookup_file
Remove the lookup file attached to a configuration.
await client.delete_configuration_lookup_file("invoice-config")
upload_batch_lookup_file
Attach a lookup file scoped to one batch. Overrides any configuration-level lookup file for that batch only.
await client.upload_batch_lookup_file(batch_guid, file_bytes, file_name="vendors.csv")
get_batch_lookup_file
Download the lookup file attached to a batch.
data = await client.get_batch_lookup_file(batch_guid)
delete_batch_lookup_file
Remove the lookup file attached to a batch.
await client.delete_batch_lookup_file(batch_guid)
Configurations
save_configuration
Save a named configuration.
from docudevs.models import UploadCommand
config = UploadCommand(
prompt="Extract invoice data",
ocr="PREMIUM"
)
await client.save_configuration("invoice-config", config)
list_configurations
List all saved configurations.
configs = await client.list_configurations()
get_configuration
Get details of a specific configuration.
config = await client.get_configuration("invoice-config")
delete_configuration
Delete a configuration.
await client.delete_configuration("invoice-config")
upload_excel_template
Attach an Excel template to a named configuration. When result_excel(...) (or wait_until_ready(..., result_format="excel")) is later called with that configuration, the result is injected into the template at its configured cell offset, preserving the template's formatting and formulas.
await client.upload_excel_template("invoice-config", template=excel_bytes)
Templates
upload_template
Upload a new document template.
with open("form.pdf", "rb") as f:
response = await client.upload_template(
name="form-template",
document=f.read(),
file_name="form.pdf",
mime_type="application/pdf"
)
list_templates
List all available templates.
templates = await client.list_templates()
metadata
Get metadata (fields) for a template.
For PDF templates uploaded moments earlier, the raw endpoint may still be preparing metadata. In that case prefer wait_for_template_metadata(...).
meta = await client.metadata("form-template")
wait_for_template_metadata
Wait until PDF template metadata is ready and return the decoded field list.
fields = await client.wait_for_template_metadata(
"form-template",
timeout=60,
poll_interval=1,
)
fill
Fill a template with data.
from docudevs.models import TemplateFillRequest
request = TemplateFillRequest(fields={"name": "John"})
response = await client.fill("form-template", request)
fill_with_retry
Fill a template while retrying transient readiness errors that can happen immediately after upload.
request = TemplateFillRequest(fields={"name": "John"})
response = await client.fill_with_retry(
"form-template",
request,
timeout=30,
poll_interval=1,
)
delete_template
Delete a template.
await client.delete_template("form-template")
upload_template_images
Upload images (logos, signatures) to blob storage for use in template filling. Returns a dict mapping each image key to its blob path reference, for use with image_ref(...) in a fill(...) call.
paths = await client.upload_template_images("invoice", {
"logo": "path/to/logo.png",
"signature": signature_bytes,
})
image_ref
Static helper. Build an image reference for a TemplateFillRequest field from a path returned by upload_template_images(...).
from docudevs.docudevs_client import DocuDevsClient
request = TemplateFillRequest(fields={
"company_name": "ACME Corp",
"logo": DocuDevsClient.image_ref(paths["logo"], width_mm=50),
})
await client.fill("invoice", request)
LLM and OCR Providers
Manage bring-your-own LLM and OCR providers and the logical key bindings that route requests to them. See Bring Your Own LLM and Bring Your Own OCR for the provider model and setup steps.
create_llm_provider, update_llm_provider, create_ocr_provider, and update_ocr_provider are thin convenience wrappers that currently send outdated field names and do not match the current provider contract. Use the generated API functions (see Bring Your Own LLM) or call the REST API directly instead of these four methods.
list_llm_providers
List LLM providers for the organization.
providers = await client.list_llm_providers()
create_llm_provider
Create an LLM provider. See the warning above before using this method.
async def create_llm_provider(self, name: str, type_: str, base_url: str | None = None, api_key: str | None = None, model: str | None = None, description: str | None = None)
get_llm_provider
Get a single LLM provider by id.
provider = await client.get_llm_provider(provider_id)
update_llm_provider
Patch update LLM provider fields (only sends provided keys). See the warning above before using this method.
async def update_llm_provider(self, provider_id: int, *, name: str | None = None, base_url: str | None = None, model: str | None = None, description: str | None = None)
delete_llm_provider
Soft delete an LLM provider.
await client.delete_llm_provider(provider_id)
list_llm_keys
List logical LLM key bindings.
keys = await client.list_llm_keys()
update_llm_key_binding
Assign or clear the provider bound to a logical LLM key. Pass provider_id=None to clear the binding.
await client.update_llm_key_binding("DEFAULT", provider_id)
list_ocr_providers
List OCR providers for the organization.
providers = await client.list_ocr_providers()
create_ocr_provider
Create an OCR provider (Azure Document Intelligence configuration). See the warning above before using this method.
async def create_ocr_provider(self, name: str, endpoint: str | None = None, api_key: str | None = None, model: str | None = None, description: str | None = None)
get_ocr_provider
Get an OCR provider by id.
provider = await client.get_ocr_provider(provider_id)
update_ocr_provider
Patch update OCR provider fields. See the warning above before using this method.
async def update_ocr_provider(self, provider_id: int, *, name: str | None = None, endpoint: str | None = None, model: str | None = None, description: str | None = None)
delete_ocr_provider
Soft delete an OCR provider.
await client.delete_ocr_provider(provider_id)
list_ocr_keys
List OCR key bindings.
keys = await client.list_ocr_keys()
update_ocr_key_binding
Assign or clear the provider bound to an OCR key binding.
await client.update_ocr_key_binding("DEFAULT", provider_id)
Embeddings
Manage bring-your-own embedding providers, the organization's default embedding binding, and per-case reindexing. See Bring Your Own Embeddings for the provider/revision/generation model.
list_embedding_providers
List embedding providers and their revisions for the organization.
providers = await client.list_embedding_providers()
create_embedding_provider
Create an embedding provider and its initial embedding revision. Changing endpoint, model, dimensions, or metric later creates a new revision; existing cases keep their current generation until an explicit reindex is started.
provider = await client.create_embedding_provider(
name="Org Azure OpenAI embeddings",
provider_type="azure-openai",
api_url="https://my-resource.openai.azure.com",
deployment_name="text-embedding-3-large",
dimensions=3072,
similarity_metric="cosine",
credential_id=credential_id,
)
get_embedding_provider
Get an embedding provider with all of its revisions.
provider = await client.get_embedding_provider(provider_id)
update_embedding_provider
Update embedding provider fields. Semantic changes (provider_type, api_url, deployment_name, dimensions, similarity_metric, request_options) create a new revision and report that existing cases need an explicit reindex; changing only the credential reference does not reindex existing cases.
async def update_embedding_provider(self, provider_id: int, *, name=None, provider_type=None, api_url=None, deployment_name=None, dimensions=None, similarity_metric=None, request_options=None, credential_id=None, enabled=None, force_disable=False, set_as_default=False)
delete_embedding_provider
Delete an embedding provider. Its disabled revisions become unavailable.
await client.delete_embedding_provider(provider_id)
get_default_embedding_binding
Get the organization's default embedding binding and rollout counters.
binding = await client.get_default_embedding_binding()
set_default_embedding_binding
Bind the organization default to an existing embedding revision. The binding applies to new case generations only; existing cases keep their active generation until reindexed.
await client.set_default_embedding_binding(revision_id)
get_embedding_overview
Get the organization embedding rollout overview (counts of cases by revision).
overview = await client.get_embedding_overview()
get_case_embedding_status
Get embedding generation status for a case, including its active and any in-progress candidate generation.
status = await client.get_case_embedding_status(case_id)
start_case_embedding_reindex
Start reindexing a case with the organization's default revision. Documents uploaded during the reindex are dual-written to both the active and candidate generations; cutover is atomic per case.
await client.start_case_embedding_reindex(case_id)
cancel_case_embedding_reindex
Cancel a running case reindex; the active generation keeps serving.
await client.cancel_case_embedding_reindex(case_id)
retry_case_embedding_reindex
Retry a failed case reindex candidate.
await client.retry_case_embedding_reindex(case_id)
Case Agent and Evaluation
Case-bound agent chat, pending actions, headless runs, holdout evaluations and memo A/B. See Case agent, Agent actions, Headless agent runs and Holdout evaluation.
agent_chat
Send a chat message to the agent. With case_id the agent works on that case, with playbook (general or investigate-flagged) and an optional context (classify:{jobId}:{rowId}). Returns the job, with jobGuid.
job = await client.agent_chat(
[{"role": "user", "content": "Summarise the flagged rows of job 55."}],
session_id="week-41",
case_id=42,
playbook="investigate-flagged",
)
agent_status
Get the status of an agent chat job, its response and its pendingActions (summaries with id, tool, toolClass, summary and expiresAt).
status = await client.agent_status(job["jobGuid"])
start_agent_run
Start a headless agent run on a case. params may hold max_rows, flags and job_id; budget may hold max_total_tokens, which is authorised when the run starts. Returns {runId, jobGuid}.
started = await client.start_agent_run(
42,
"investigate-flagged",
params={"job_id": 55, "max_rows": 10},
budget={"max_total_tokens": 60000},
)
get_agent_run
Get the state, budget, progress, pending action ids and report of a run.
run = await client.get_agent_run(42, started["runId"])
wait_for_agent_run
Poll a run until it completes. Raises AgentRunFailed when the run fails or is cancelled, and TimeoutError when it runs longer than timeout.
run = await client.wait_for_agent_run(42, started["runId"], timeout=1800)
cancel_agent_run
Cancel a run; it stops after its current turn. Agent tokens cannot cancel.
await client.cancel_agent_run(42, started["runId"])
list_agent_runs
List the runs of a case, newest first, as {items, continuation?}. Pass origin_job_id for the runs of one classify job and status for one state.
runs = await client.list_agent_runs(42, origin_job_id=55, status="COMPLETED")
list_agent_actions
List the case inbox: {items, nextBefore?}, newest first. status is pending, confirmed, rejected or expired.
pending = await client.list_agent_actions(42, status="pending", limit=20)
confirm_agent_action
Confirm a pending action as the signed-in person. The stored request is replayed; a repeated confirm returns the stored result.
result = await client.confirm_agent_action(9001)
reject_agent_action
Reject a pending action, optionally with a reason.
await client.reject_agent_action(9002, reason="Use the 7.31 subtree instead")
start_holdout_eval
Start a holdout evaluation. Each variant is {"name", "memo_include"?, "config"?}; the first variant is the baseline. Pass group_field so the held-out split groups near-duplicates. Returns {evalId, status, jobGuid}.
started = await client.start_holdout_eval(
42,
[{"name": "baseline"}, {"name": "with-rule", "memo_include": ["m_88"]}],
sample_size=200,
seed=7,
group_field="base_product_id",
)
get_holdout_eval
Get the status, variants and, once completed, the report of an evaluation.
evaluation = await client.get_holdout_eval(42, started["evalId"])
wait_for_eval
Poll an evaluation until it completes. Raises EvalFailed when it fails and TimeoutError when it runs longer than timeout.
evaluation = await client.wait_for_eval(42, started["evalId"], timeout=3600)
compare_holdout_evals
Score two completed evaluations against each other without classifying again. Answers 409 when the samples differ.
comparison = await client.compare_holdout_evals(42, 301, 302, baseline_variant="baseline")
evaluate_memo_entry
Evaluate a proposed memo entry (memo A/B): run A uses the active memo, run B adds the entry. Returns {evalId, status}. It approves nothing.
memo_eval = await client.evaluate_memo_entry(42, entry["id"], sample_size=200, seed=7, group_field="base_product_id")
search_categories
Search or browse the categories of a tree version by name, code or parent.
hits = await client.search_categories(42, version_id, query="fiction", size=20)
Model Credentials
Shared credentials referenced by embedding providers (and other bring-your-own integrations) by id, so secrets are never round-tripped back to callers. See Model Credentials.
list_model_credentials
List safe metadata (no secrets) for shared model credentials.
credentials = await client.list_model_credentials()
create_model_credential
Create a shared API-key or Entra client-secret credential. Secrets are write-only; the returned object contains metadata and the credential ID, which can be passed to embedding-provider methods.
credential = await client.create_model_credential(
name="Org Azure OpenAI key",
secret="...",
auth_type="API_KEY",
)
rotate_model_credential
Rotate a shared credential's secret without changing embedding vectors.
await client.rotate_model_credential(credential_id, secret="new-secret")
delete_model_credential
Delete a shared credential that is no longer referenced by any provider.
await client.delete_model_credential(credential_id)
AcroForm PDF Metadata
extract_acroform_metadata
Upload a PDF directly to /document/acroform-metadata and return the rich AcroForm metadata structure without creating a job GUID.
metadata = await client.extract_acroform_metadata(
document=pdf_bytes,
file_name="fillable-form.pdf",
mime_type="application/pdf",
)
get_acroform_metadata
Fetch the stored AcroForm metadata artifact from an async processed job or a pdf-acroform operation job.
job_guid = await client.submit_and_process_document(
document=pdf_bytes,
document_mime_type="application/pdf",
acro_form_metadata=True,
)
metadata = await client.get_acroform_metadata(job_guid)
The direct helper is for metadata-only PDF uploads. The async helper is for workflows where the same job also needs source locations, rendered page images, extraction, or overlays.
For generated AcroForm PDFs, this metadata reflects the widgets embedded in the output PDF. Use get_pdf_acroform_field_definitions(...) when you need the normalized editable boxes that were used to generate those widgets.
Agent Chat
agent_chat
Send a chat message to the agent and receive a job GUID.
response = await client.agent_chat(
messages=[{"role": "user", "content": "Help me extract invoice line items"}],
session_id="session-123"
)
agent_status
Check the status of an agent chat job.
status = await client.agent_status(response["jobGuid"])
agent_chat_and_wait
Send a message and wait for the completed response.
result = await client.agent_chat_and_wait(
messages=[{"role": "user", "content": "Create a schema for insurance claims"}],
session_id="session-123"
)
print(result["response"]["message"])
Cases
create_case
Create a new case (collection of documents).
from docudevs.models import CreateCaseBody
case = await client.create_case(
body=CreateCaseBody(name="Q1 Invoices")
)
list_cases
List all cases.
cases = await client.list_cases()
get_case
Get a specific case. Accepts an int or str case id (coerced to int).
case = await client.get_case(123)
update_case
Update an existing case.
await client.update_case(123, body)
delete_case
Delete a case.
await client.delete_case(123)
list_case_documents
List documents within a case (paginated).
page = await client.list_case_documents(123, page=0, size=20)
get_case_document
Get details for a document stored in a case.
document = await client.get_case_document(123, "doc-uuid")
delete_case_document
Delete a document from a case.
await client.delete_case_document(123, "doc-uuid")
upload_case_document
Upload a document to a case.
from docudevs.models import UploadCaseDocumentBody
from docudevs.types import File
await client.upload_case_document(
case_id=123,
body=UploadCaseDocumentBody(
document=File(payload=data, file_name="doc.pdf")
)
)
get_document_summary
Get the AI-generated summary for a specific document in a case.
result = await client.get_document_summary(case_id=123, document_id="doc-uuid")
summary = result.parsed
print(summary["filename"]) # "invoice.pdf"
print(summary["summary"]["document_type"]) # "invoice"
list_case_summaries
List AI-generated summaries for all documents in a case.
result = await client.list_case_summaries(case_id=123)
for doc in result.parsed:
print(f"{doc['filename']}: {doc['summary']['document_type']}")
Knowledge Bases
A knowledge base is a case promoted for retrieval and downstream features such as contract analysis. See Cases.
list_knowledge_bases
List cases marked as knowledge bases.
knowledge_bases = await client.list_knowledge_bases()
promote_knowledge_base
Mark a case as a knowledge base.
await client.promote_knowledge_base(case_id)
get_knowledge_base
Retrieve a knowledge base by its case id.
kb = await client.get_knowledge_base(case_id)
delete_knowledge_base
Remove the knowledge base designation from a case. The case itself is not deleted.
await client.delete_knowledge_base(case_id)
Contract Analysis
Contract analysis compiles a knowledge base into a reviewable profile, runs immutable analysis runs against it, and supports expert review and test-suite curation. See Contract Analysis for the profile/draft/publish lifecycle and the run/review model.
get_contract_analysis_profile
Get a contract-analysis profile draft or its currently published version.
profile = await client.get_contract_analysis_profile(case_id, view="draft")
generate_contract_analysis_profile
Start profile compilation from the eligible knowledge-base documents. Returns a generation job whose proposal can be compared and applied.
generation = await client.generate_contract_analysis_profile(case_id)
get_contract_analysis_generation_comparison
Get the immutable three-way comparison (previous / current / proposed) for a generated proposal.
comparison = await client.get_contract_analysis_generation_comparison(case_id, generation_job_guid)
apply_contract_analysis_generation
Apply an explicitly reviewed generation against the exact draft snapshot it was compared to.
async def apply_contract_analysis_generation(self, case_id, generation_job_guid, *, expected_draft_revision: int, expected_draft_fingerprint: str, decisions: Mapping[str, Mapping[str, Any]])
get_contract_analysis_source_authority
Get the source-authority decision history for a profile.
history = await client.get_contract_analysis_source_authority(case_id)
record_contract_analysis_source_authority_decision
Record a source-authority decision at an observed decision revision.
async def record_contract_analysis_source_authority_decision(self, case_id, *, observed_revision: int, decision_type: str, content: Mapping[str, Any], reason: str, element_lineage_id: str | None = None, element_action: str | None = None, tombstone: bool = False, generation_job_guid: str | None = None, draft_revision: int | None = None)
update_contract_analysis_draft
Replace the draft profile at the observed revision (optimistic concurrency on draft_revision).
await client.update_contract_analysis_draft(case_id, draft_revision=3, profile=updated_profile)
publish_contract_analysis_profile
Publish a validated draft profile at the observed revision.
await client.publish_contract_analysis_profile(
case_id,
draft_revision=3,
acknowledged_warning_codes=["missing_termination_clause"],
)
get_contract_analysis_test_suite
Get the current immutable test-suite revision for a knowledge base.
suite = await client.get_contract_analysis_test_suite(case_id)
update_contract_analysis_test_suite
Create the next suite revision from the observed revision and a list of test cases.
await client.update_contract_analysis_test_suite(case_id, revision=2, cases=[...])
create_contract_analysis_trial
Explicitly launch an exploratory or scored draft-profile trial.
trial = await client.create_contract_analysis_trial(
case_id,
anchor_job_guid=job_guid,
idempotency_key="trial-1",
trial_kind="scored",
)
get_contract_analysis_trial
Read status and the immutable report for a trial.
trial = await client.get_contract_analysis_trial(case_id, trial_id)
attest_contract_analysis_trial
Record an authenticated expert's approval of a passing trial report.
await client.attest_contract_analysis_trial(case_id, trial_id, report_id=report_id)
submit_contract_analysis
Submit contract analysis for a completed parent job against a published knowledge-base profile.
submission = await client.submit_contract_analysis(job_guid, knowledge_base_id=knowledge_base_id)
submit_and_wait_for_contract_analysis
Submit contract analysis and poll until its result is available.
result = await client.submit_and_wait_for_contract_analysis(
job_guid,
knowledge_base_id=knowledge_base_id,
timeout=120,
)
create_contract_analysis_run
Create an immutable, multi-document contract-analysis run and return its run identity. mode is "published" (default) or "draft_trial".
run = await client.create_contract_analysis_run(
anchor_job_guid,
knowledge_base_id=knowledge_base_id,
idempotency_key="run-1",
)
get_contract_analysis_run
Get status for exactly one immutable run.
run = await client.get_contract_analysis_run(run_id)
get_contract_analysis_run_result
Get the result for exactly one immutable run.
result = await client.get_contract_analysis_run_result(run_id)
get_contract_analysis_run_reviews
Get current human review dispositions for an immutable run.
reviews = await client.get_contract_analysis_run_reviews(run_id)
put_contract_analysis_run_review
Append an expert disposition (accepted, corrected, dismissed, unresolved) to one captured finding without changing the machine result.
await client.put_contract_analysis_run_review(
run_id, criterion_id, target_key,
result_fingerprint=fingerprint,
disposition="accepted",
expected_review_revision=0,
idempotency_key="review-1",
)
propose_contract_analysis_finding_test_case
Add an unapproved finding expectation to a new test-suite revision, seeded from one immutable run finding.
async def propose_contract_analysis_finding_test_case(self, case_id: int, *, run_id: str, result_fingerprint: str, criterion_id: str, target_key: str, name: str, expected_assessment: str, reason: str, expected_suite_revision: int, idempotency_key: str, scenario_tags: list[str] | None = None)
Operations
submit_and_wait_for_error_analysis
Run error analysis on a completed job.
analysis = await client.submit_and_wait_for_error_analysis(job_guid)
submit_operation
Submit an operation for a completed job without parameters or waiting.
response = await client.submit_operation(job_guid, "error-analysis")
submit_operation_with_parameters
Submit an operation with an optional LLM type override and custom parameters, without waiting.
async def submit_operation_with_parameters(self, job_guid: str, operation_type: str, llm_type: Optional[str] = None, custom_parameters: Optional[dict] = None)
submit_and_wait_for_operation
Submit an operation (no extra parameters) and poll until it completes.
result = await client.submit_and_wait_for_operation(job_guid, "error-analysis", timeout=120)
get_operation_status
Get the status of all operations submitted for a job.
statuses = await client.get_operation_status(job_guid)
get_operation_result
Get the result of one specific operation type for a job.
result = await client.get_operation_result(job_guid, "error-analysis")
create_generative_task
Create a generative task for a completed job without waiting for it. Prefer submit_and_wait_for_generative_task unless you need to poll independently.
async def create_generative_task(self, parent_job_id: str, prompt: str, model: Optional[str] = None, temperature: Optional[float] = None, max_tokens: Optional[int] = None)
submit_and_wait_for_generative_task
Run a generative AI task on a completed job.
task = await client.submit_and_wait_for_generative_task(
parent_job_id=job_guid,
prompt="Summarize this document",
model="DEFAULT"
)
# Result is in task.result (JSON string)
submit_and_wait_for_operation_with_parameters
Run an operation with custom parameters.
result = await client.submit_and_wait_for_operation_with_parameters(
job_guid=job_guid,
operation_type="error-analysis",
llm_type="HIGH",
custom_parameters={"focus": "dates"}
)
submit_and_wait_for_image_selection
Select relevant figures from a completed job that extracted figures.
selection = await client.submit_and_wait_for_image_selection(
job_guid,
prompt="Return all diagrams from the document",
top_k=5,
match_mode="all",
use_vision=False
)
import json
selection_payload = json.loads(selection.result)
selected = selection_payload.get("selected", [])
submit_pdf_acroform_operation
Queue pdf-acroform on a completed PDF job.
response = await client.submit_pdf_acroform_operation(
job_guid=parent_job_guid,
llm_type="DEFAULT",
ocr="PREMIUM",
page_range=[1, 2],
min_confidence=0.35,
max_fields_per_page=300,
)
print(response.parsed["jobGuid"])
submit_and_wait_for_pdf_acroform_operation
Run pdf-acroform, wait for completion, and download the generated fillable PDF.
conversion = await client.submit_and_wait_for_pdf_acroform_operation(
parent_job_guid,
ocr="PREMIUM",
min_confidence=0.35,
max_fields_per_page=300,
save_to="fillable.pdf",
)
print(conversion.operation_job_guid)
get_pdf_acroform
Download the generated PDF bytes for a pdf-acroform or pdf-acroform-apply operation job.
pdf_bytes = await client.get_pdf_acroform(operation_job_guid, save_to="fillable.pdf")
get_pdf_acroform_field_definitions
Fetch the normalized editable field definitions for a pdf-acroform operation.
entryBbox uses normalized page-image coordinates from 0..1, which makes this artifact the correct input for review tooling and manual edits.
definitions = await client.get_pdf_acroform_field_definitions(operation_job_guid)
fields = definitions["fieldDefinitions"] if definitions else []
submit_pdf_acroform_apply_operation
Queue reviewed field definitions to regenerate the PDF without rerunning visual detection.
response = await client.submit_pdf_acroform_apply_operation(
parent_job_guid,
field_definitions=edited_fields,
source_operation_guid=operation_job_guid,
)
print(response.parsed["jobGuid"])
submit_and_wait_for_pdf_acroform_apply_operation
Submit reviewed field definitions, wait for completion, and download the regenerated PDF.
applied = await client.submit_and_wait_for_pdf_acroform_apply_operation(
parent_job_guid,
field_definitions=edited_fields,
source_operation_guid=operation_job_guid,
save_to="fillable-reviewed.pdf",
)
print(applied.operation_job_guid)
Document Outline
Document-outline extraction produces a structural outline of a document (sections/headers), either as a map-reduce split strategy or as a standalone follow-up operation on an existing job. See Operations.
submit_document_outline_operation
Submit a document-outline-only follow-up operation for an existing OCR/extraction job.
async def submit_document_outline_operation(self, job_guid: str, *, llm_type: Optional[str] = None, pages_per_chunk: Optional[int] = None, overlap_pages: Optional[int] = None, parallel_processing: Optional[bool] = None)
submit_and_wait_for_document_outline_operation
Submit an outline-only operation and wait for the outline artifact.
outline = await client.submit_and_wait_for_document_outline_operation(job_guid, timeout=180)
print(outline.document_outline)
get_document_outline
Get the document-outline artifact for a DOCUMENT_OUTLINE map-reduce job or outline operation.
outline = await client.get_document_outline(guid)
wait_until_ready_with_document_outline
Wait for completion, then return both the JSON result and the document-outline artifact as a StructuredResultWithDocumentOutline(result=..., document_outline=...).
bundle = await client.wait_until_ready_with_document_outline(guid, timeout=180)
Map-Reduce Helpers
submit_and_process_document_map_reduce
Process large documents using map-reduce strategy.
job_guid = await client.submit_and_process_document_map_reduce(
document=doc_bytes,
document_mime_type="application/pdf",
prompt="Extract line items",
split_type="page",
pages_per_chunk=5,
overlap_pages=1,
dedup_key="sku",
parallel_processing=True
)
submit_and_wait_for_map_reduce
Run map-reduce on an already-processed job without re-uploading or re-running OCR. This is the map-reduce equivalent of submit_and_wait_for_generative_task.
# First: process a document normally (OCR runs here)
job_guid = await client.submit_and_process_document(
document=doc_bytes,
document_mime_type="application/pdf",
prompt="Extract summary",
)
await client.wait_until_ready(job_guid)
# Later: re-run with map-reduce — no new upload, reuses OCR from parent job
result = await client.submit_and_wait_for_map_reduce(
parent_job_id=job_guid,
prompt="Extract all line items (sku, description, quantity, total)",
schema='{"type":"array","items":{"type":"object"}}',
split_type="page",
pages_per_chunk=5,
overlap_pages=1,
dedup_key="sku",
parallel_processing=True,
timeout=300,
result_format="json"
)
print(result["records"])
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
parent_job_id | str | required | GUID of the completed job whose document to re-process. |
prompt | str | "" | Extraction instructions. |
schema | str | "" | JSON schema for structured extraction. |
split_type | str | "page" | Chunk strategy: "page" or "markdown_header". |
split_header_level | int | 2 (markdown mode) | Header level (1 or 2) used when split_type="markdown_header". |
pages_per_chunk | int | 1 | Pages per chunk. |
overlap_pages | int | 0 | Overlapping pages between chunks. |
dedup_key | str | None | Required when overlap_pages > 0. |
parallel_processing | bool | False | Run chunks in parallel. |
mime_type | str | "application/pdf" | Document MIME type. |
timeout | int | 180 | Max seconds to wait. |
poll_interval | float | 5.0 | Seconds between status polls. |
result_format | str | "json" | "json", "csv", "excel", or None. |
When split_type="markdown_header", overlap_pages and dedup_key are not supported.
All other map-reduce parameters (header_options, header_schema, header_prompt, stop_when_empty, empty_chunk_grace, ocr, llm, trace, page_range, tools, etc.) are also accepted.
build_upload_command_map_reduce
Build the raw UploadCommand with map-reduce parameters without submitting it. Used internally by submit_and_process_document_map_reduce and process_document_map_reduce.
command = client.build_upload_command_map_reduce(
mime_type="application/pdf",
prompt="Extract line items",
pages_per_chunk=5,
)
process_document_map_reduce
Process an already-uploaded document using map-reduce chunking parameters. Takes the same map-reduce parameters as submit_and_process_document_map_reduce, but skips the upload step.
await client.process_document_map_reduce(
guid,
prompt="Extract line items",
pages_per_chunk=5,
overlap_pages=1,
)
LLM Tracing
get_trace
Get the LLM trace for a completed job (only available if trace=True was set).
trace = await client.get_trace(job_guid)
if trace:
print(f"Total tokens: {trace['total_tokens']}")
print(f"LLM calls: {trace['total_llm_calls']}")
for event in trace['events']:
print(f" {event['type']}: {event['name']}")
get_image
Get a page thumbnail image from a processed job.
image_bytes = await client.get_image(job_guid, page_index=0)
if image_bytes:
with open("page_0.png", "wb") as f:
f.write(image_bytes)
get_figures_metadata
Get extracted figure metadata for a job.
metadata = await client.get_figures_metadata(job_guid)
images = metadata.get("images", []) if metadata else []
get_figure_image
Download a figure image by ID.
figure_id = images[0]["id"]
image_bytes = await client.get_figure_image(job_guid, figure_id)
if image_bytes:
with open("figure_0.png", "wb") as f:
f.write(image_bytes)
Job Management
delete_job
Delete a job and its associated data. Jobs must be in a terminal state (COMPLETED, ERROR, TIMEOUT, or PARTIAL). Jobs older than 14 days are automatically purged, so this method is primarily for cleaning up recent jobs.
result = await client.delete_job(job_guid)
if result.status_code == 200:
print(f"Deleted {result.parsed['jobsDeleted']} job(s)")
Parameters:
guid(str): The job GUID to delete
Returns: A response object with:
status_code(int): HTTP status (200 on success, 404 if not found)parsed(dict): ContainsjobsDeleted,errorson success
Note: Deleting a job removes all associated data including uploaded documents, OCR results, and extracted data. Usage/billing records are preserved but disassociated from the deleted job.
Enabling Tracing
Pass trace=True to any processing method:
job_guid = await client.submit_and_process_document(
document=doc_bytes,
document_mime_type="application/pdf",
prompt="Extract data",
trace=True # Enable LLM tracing
)
Error Handling
The SDK raises exceptions for API errors.
try:
await client.get_configuration("non-existent")
except Exception as e:
print(f"Error: {e}")