Python SDK & CLI
Ostatnia aktualizacja: 2026-10-15
Suparse Python SDK
Official Python SDK and CLI for the Suparse Document Processing API.
Suparse is an AI-powered document processing API for extracting structured data from any document type, including invoices, receipts, bank statements, purchase orders and many more. This SDK wraps the REST API with a Python client and CLI.
Requirements
Python 3.10+ is required. pip install suparse automatically installs the SDK
dependencies: httpx, pydantic, pydantic-settings, and tenacity.
Installation
pip install suparseAuthentication
You'll need an API key to use the SDK or CLI. To obtain one:
- Sign in at suparse.com
- Go to the API Keys tab
- Enter a key name and click Generate New Key
- Copy the key value — it will be shown only once
Set it as an environment variable:
export SUPARSE_API_KEY="your_api_key_here"For the CLI, you can also store it in ~/.config/suparse/config.json:
{
"apiKey": "your_api_key_here"
}Or pass it directly to the SDK constructor (see below).
Quick Start
With SUPARSE_API_KEY set, process a document from the terminal:
suparse process invoice.pdf -o results.jsonOr use Python synchronously:
from suparse import SuparseClient
with SuparseClient() as client:
result = client.extract("invoice.pdf")
for document in result.succeeded:
print(document.original_file, document.data)
for failure in result.failed:
print(f"Failed: {failure.file}: {failure.error}")For an async application:
import asyncio
from suparse import AsyncSuparseClient
async def main():
async with AsyncSuparseClient() as client:
result = await client.extract("invoice.pdf")
for document in result.succeeded:
print(document.original_file, document.data)
for failure in result.failed:
print(f"Failed: {failure.file}: {failure.error}")
asyncio.run(main())Always inspect result.failed, even for a single file: per-file failures are
returned there without raising an exception. Setup or cleanup errors can still
raise exceptions. See Error Handling.
CLI Usage
Run suparse --help or suparse process --help for full usage information.
Set your API key and process a file directly from the terminal. The SDK will auto-upload, poll, and download the resulting JSON.
Process a Document
export SUPARSE_API_KEY="your_api_key_here"
# Auto-detect template
suparse process path/to/invoice.pdf -o results.json
# Use specific template without auto-splitting
suparse process path/to/invoice.pdf --template-id YOUR_TEMPLATE_ID
# Auto-split a multi-page PDF containing mixed document types (e.g. receipts + bank statements)
suparse process path/to/merged.pdf --with-split
# Use specific template with auto-splitting
suparse process path/to/invoice.pdf --template-id YOUR_TEMPLATE_ID --with-split
# Process and auto-delete documents from server after download
suparse process path/to/invoice.pdf --cleanup
# Export directly to XLSX
suparse process path/to/invoice.pdf --format xlsx
# Choose the flat XLSX layout
suparse process path/to/invoice.pdf --format xlsx --xlsx-layout flat
# Export CSV using original template columns
suparse process path/to/invoice.pdf --format csv --export-type original
# Process an encrypted PDF without putting the password in shell history
suparse process path/to/encrypted.pdf --prompt-pdf-password
# Assign uploaded documents to a folder
suparse process path/to/invoice.pdf --folder-id <folder-id>
# Start automatic schema creation and wait for the generated template
suparse quick-create path/to/example.pdf --wait
# Start schema creation for an encrypted PDF without putting the password in shell history
suparse quick-create path/to/encrypted.pdf --prompt-pdf-password
# Inspect a previously started schema-creation run
suparse quick-create-status <run-id>Process a Folder
Process all supported files (.pdf, .jpg, .jpeg, .png, .heic, .heif) in a folder. All files are uploaded and polled individually. By default, results are combined into a single JSON file.
Use --format csv or --format xlsx to export spreadsheet files; exports that
produce multiple files may be returned as a ZIP. Use --format google_sheets
to export to Google Sheets (requires the Google Sheets integration).
# Process all supported files in a folder
suparse process --folder path/to/receipts/
# Output to a specific file (default: {folder_name}_results.json)
suparse process --folder path/to/receipts/ -o all_results.json
# Process a folder with a specific template
suparse process --folder path/to/receipts/ --template-id YOUR_TEMPLATE_ID
# Process a folder with auto-splitting enabled
suparse process --folder path/to/receipts/ --with-split
# Process a folder and auto-delete documents from server after download
suparse process --folder path/to/receipts/ --cleanup
# Export a folder to CSV, XLSX, or Google Sheets
suparse process --folder path/to/receipts/ --format csv
suparse process --folder path/to/receipts/ --format xlsx -o ./exports
suparse process --folder path/to/receipts/ --format google_sheetsExport Existing Documents
Export documents by their IDs without uploading them again:
suparse export DOCUMENT_ID --format json -o results.json
suparse export DOCUMENT_ID --format xlsx --xlsx-layout flat -o export.xlsx
suparse export DOCUMENT_ID --format csv --export-type original -o export.csv
suparse export DOCUMENT_ID --format xlsx --wait-timeout 900 \
--idempotency-key 44444444-4444-4444-8444-444444444444 -o export.xlsx--wait-timeout controls how long to wait for a background export (default: 900
seconds). --idempotency-key accepts a UUID; save it to recover an uncertain
submission. Accepted job IDs and recovery instructions are printed to stderr.
Choose an Export Mode and XLSX Layout
--export-type controls which template defines the columns for CSV, XLSX, and
Google Sheets. The SDK uses the same values through ExportType.
| Mode | Column selection | When to use it |
|---|---|---|
original | Each document's historical processing template | Preserve the fields and columns used when that document was processed |
unified | Documents grouped by template group, using the latest active template's columns | Combine documents processed with different versions of the same template for reporting |
Unified export projects existing extracted values onto the selected columns; it does not reprocess documents. Fields missing from older results appear blank. Different template groups remain separate; an export producing multiple files may be returned as a ZIP.
--xlsx-layout controls how XLSX data is arranged, independently of export mode:
| Layout | Organization | When to use it |
|---|---|---|
standard (default) | Document-level fields in a summary sheet; line items in a separate items sheet | Review document summaries and item details separately |
flat | Document-level fields repeated beside each line-item row in a data sheet | Filter, build pivot tables, or import rows into another tool |
For example, an invoice INV-001 from Acme with two items would have these
simplified data sheets (actual columns come from your template):
Standard — summary sheet
| Invoice | Supplier |
|---|---|
| INV-001 | Acme |
Standard — items sheet
| Item | Amount |
|---|---|
| Paper | 10 |
| Ink | 20 |
Flat — data sheet
| Invoice | Supplier | Item | Amount |
|---|---|---|---|
| INV-001 | Acme | Paper | 10 |
| INV-001 | Acme | Ink | 20 |
The example illustrates unified output; original standard output presents
summary fields as key/value pairs. Unified workbooks also include a FileName
column to identify the source document.
suparse export DOCUMENT_ID --format xlsx --export-type unified --xlsx-layout standard -o standard.xlsx
suparse export DOCUMENT_ID --format xlsx --export-type unified --xlsx-layout flat -o flat.xlsxRead Task Results and Resume Exports
# Read currently available results; these commands do not wait for processing.
suparse task-results TASK_ID
suparse task-results TASK_ID --jsonl
suparse task-results TASK_ID --output results.json --overwrite
suparse task-results TASK_ID --single-page --cursor TOKEN --page-size 50
# Inspect, wait for, and download a background export.
suparse export-job-status JOB_ID --format json
suparse export-job-wait JOB_ID --timeout 900 --format json
suparse export-job-download JOB_ID -o export.xlsx --overwritetask-results prints a JSON array by default, streams JSONL with --jsonl, or
prints a page containing documents and next_cursor with --single-page.
--page-size accepts 1–100 (default: 100). --cursor requires --single-page;
--jsonl and --single-page are mutually exclusive.
Task-result file output is saved only after all requested pages are read
successfully. Replacing an existing file requires --overwrite. JSONL written
to stdout may contain partial results if a later page fails; errors are printed
to stderr.
export-job-download requires a completed job and does not wait. Omit -o to
use the artifact filename in the current directory, or pass an existing output
directory. Replacing a file requires --overwrite. A wait timeout does not
cancel the server job; run export-job-wait again to resume waiting.
CLI exit codes are 0 for success, 1 for execution failure, and 2 for invalid arguments. Check schema-creation result status as described in Automatic Schema Creation: starting a run successfully does not mean schema creation has completed.
Delete Documents
# Delete one or more documents by ID (prompts for confirmation)
suparse delete <document_id>
suparse delete <id1> <id2> <id3>
# Skip confirmation prompt
suparse delete <id1> <id2> -yDeleting a parent document automatically deletes all its child documents (server-side cascade).
List Available Templates
Templates define how a document type (invoice, receipt, bank statement, etc.) is parsed. Before processing a document, check which templates are already assigned to your account:
# List templates assigned to your account (table format)
suparse templates
# List templates in JSON format
suparse templates --format json
# Include all system templates (not yet assigned to your account)
suparse templates --include-system
# Request complete template records, including schema and saved document IDs
suparse templates --view full --format jsonThe recommended way to process documents is with auto-split enabled (--with-split), which handles both single-type and mixed document types automatically:
suparse process path/to/documents.pdf --with-split -o results.jsonIf you consistently process one document type, look up the template ID and pass it directly:
- Run
suparse templatesto see templates assigned to your account. - Use the matching template ID:
suparse process invoice.pdf --template-id <id> -o results.json - If no template matches, run
suparse templates --include-systemto browse all system templates. Assign one to your account via the Suparse UI. - If no system template fits, create a custom template using the template creator in the Suparse UI.
Configuration
The CLI reads settings from environment variables or a .env file in the working directory:
| Variable | Default | Description |
|---|---|---|
SUPARSE_API_URL | https://api.suparse.com/api/v1/ | API base URL |
SUPARSE_API_KEY | — | Your API key (required) |
POLL_INTERVAL | 5 | Seconds between polling attempts |
MAX_POLL_ATTEMPTS | 300 | Max polling attempts before timeout |
LOG_LEVEL | INFO | Logging level |
Priority: CLI flags > environment variables > .env file > defaults.
For API keys, the CLI also checks ~/.config/suparse/config.json after SUPARSE_API_KEY and .env. The config file should contain a JSON object with an apiKey string.
Global Options
Place global options before the subcommand, for example
suparse --verbose process invoice.pdf. Use suparse --version to print the
installed CLI version.
| Option | Description |
|---|---|
--api-url | API URL (default: from SUPARSE_API_URL env var) |
--api-key | API Key (default: from SUPARSE_API_KEY env var) |
-v, --verbose | Enable verbose (DEBUG) output |
CLI Options
| Command | Option | Description |
|---|---|---|
process | --folder | Process all supported files in a folder (mutually exclusive with file path) |
process, export | -o, --output | Output file path or existing output directory; omit to use a default filename |
process | --template-id | Template ID to use (default: auto-detect) |
process | --with-split | Auto-split multi-page PDFs containing mixed document types (e.g. receipts + bank statements) so each is processed with the correct template (default: off) |
process | --cleanup | Delete uploaded documents after processing; cleanup is deferred if an export may still be running (default: off) |
process, export | --format | Export format: json, csv, xlsx, or google_sheets (default: json) |
process, export | --export-type | Export mode for CSV, XLSX, and Google Sheets: unified or original (default: unified) |
process, export | --xlsx-layout | XLSX layout: standard or flat (default: standard) |
process | --folder-id | Folder ID applied to every uploaded input |
process | --prompt-pdf-password | Prompt securely for an encrypted PDF password |
templates | --format | Output format: table or json (default: table) |
templates | --include-system | Include system templates not yet assigned to your account (default: off) |
templates | --view | Template response view: summary or full (default: summary) |
quick-create | --wait | Wait for automatic schema creation to reach a terminal state |
quick-create | --format | Output format: table or json (default: table) |
quick-create | --prompt-pdf-password | Prompt securely for an encrypted PDF password |
quick-create-status | --format | Output format: table or json (default: table) |
delete | -y, --yes | Skip confirmation prompt |
export | --wait-timeout | Background completion wait in seconds (default: 900) |
export | --idempotency-key | UUID key to retain for submission recovery |
task-results | --jsonl, --single-page | Stream records or return a single page (mutually exclusive) |
task-results | --cursor, --page-size | Continuation token (single-page only) and page size from 1–100 |
task-results, export-job-download | -o, --output, --overwrite | Save output; explicitly allow replacing an existing file |
export-job-status, export-job-wait | --format | Output format: table or json (default: table) |
export-job-wait | --timeout | Local completion wait in seconds (default: 900) |
Python SDK Usage
The SDK provides both synchronous and asynchronous clients. Both manage connections, process multiple inputs concurrently, and retry eligible transient failures. Use the synchronous client in synchronous code and the asynchronous client in an async application.
The Quick Start shows complete examples for both clients. The
examples below use SuparseClient unless they demonstrate async-specific behavior.
With AsyncSuparseClient, use async with and await the corresponding methods;
options and result types are the same.
The client reads SUPARSE_API_KEY and SUPARSE_API_URL from environment variables or a .env file by default, so you can simply use SuparseClient() or AsyncSuparseClient() if those are set.
Use a context manager to close connections automatically, or call client.close()
(await client.close() for the async client).
Extract One or More Documents
extract() is the primary API. It accepts a single file, a list of files, or any iterable (like Path.glob). Each input can be a string path, a Path object, or an open file handle.
BatchResult.total counts input sources. BatchResult.succeeded contains the
task export groups returned by the API, so one input can produce multiple
successful entries when splitting or template grouping is involved. Progress
callbacks run once per returned export group (or once for a failed input).
Callbacks preserve API order within one input, but callbacks from concurrently
processed inputs may be interleaved.
from pathlib import Path
from suparse import FailedResult, SuparseClient
def print_progress(result):
if isinstance(result, FailedResult):
print(f"Failed: {result.file}: {result.error}")
else:
print(f"Done: {result.original_file}")
with SuparseClient() as client:
# A list can mix string paths and Path objects. A glob iterable also works:
# files=Path("./receipts/").glob("*.pdf")
result = client.extract(
files=["./receipts/jan.pdf", Path("./receipts/feb.pdf")],
on_progress=print_progress,
)
for document in result.succeeded:
print(document.original_file, document.data, document.document_ids)
for failure in result.failed:
print(failure.file, failure.error)
print(f"Input files: {result.total}")document.data contains the extracted fields. Use document.documents for the
DocumentExport records, including credits_used, template_id, document_id,
file_name, page_start, and page_end. Serialize the complete export group
with document.model_dump(mode="json").
Extract a Folder
extract_folder() discovers supported files and delegates to extract(). The
default pattern "*" scans the immediate directory; use pattern="**/*" to
include subdirectories. A pdf_password or folder_id passed to extract() or
extract_folder() applies to every input. Use separate calls when inputs need
different values.
from suparse import SuparseClient
with SuparseClient() as client:
result = client.extract_folder(
"./receipts/",
template_id="YOUR_TEMPLATE_ID",
split=True,
cleanup=True,
)
for document in result.succeeded:
print(document.original_file, document.data)
for failure in result.failed:
print(failure.file, failure.error)For async code, use result = await client.extract_folder(...) inside an
async with AsyncSuparseClient() block, then inspect the same result lists.
Automatic Schema Creation
Create a template from an example document with
start_quick_schema_creation(). It accepts a string path, Path, or open binary
stream and returns a typed result containing a run ID. Use
get_quick_schema_creation(run_id) to check status once, or wait_for_quick_schema_creation(run_id) to wait for a terminal
result. Inspect result.status: failed and completed_with_errors runs are
returned as typed results, including error and failed-document details.
from pathlib import Path
from suparse import SuparseClient
with SuparseClient() as client:
started = client.start_quick_schema_creation("example.pdf")
# Persist the ID before waiting so a later timeout can be recovered.
Path("schema-run-id.txt").write_text(started.run_id, encoding="utf-8")
result = client.wait_for_quick_schema_creation(started.run_id)
print(result.status, result.model_dump(mode="json"))Use start_quick_schema_creation(..., pdf_password=...) for encrypted PDFs.
The SDK leaves caller-owned streams open. Start requests are attempted once
unless both upload_batch_id and source_upload_id are supplied for an existing
batch source. If a start request fails without a response, follow
Schema Creation Recovery before submitting again.
The quick-create and quick-create-status CLI commands return exit code 1 for
failed runs and for completed_with_errors; queued, processing, and fully
completed results return 0.
Error Handling
All SDK exceptions inherit from SuparseError. extract() and
extract_folder() collect per-file processing errors in result.failed, even
for a single input. Check that list after every call. Setup or cleanup errors
can still raise exceptions.
Low-level methods raise exceptions directly, so you can handle specific types:
from suparse import SuparseClient
from suparse.exceptions import (
SuparseError,
SuparseAuthError,
SuparseNetworkError,
)
with SuparseClient(api_key="your_api_key_here") as client:
try:
client.list_templates()
except SuparseAuthError:
print("Invalid API key")
except SuparseNetworkError:
print("Connection failed")
except SuparseError as e:
print(f"Unexpected error: {e}")With AsyncSuparseClient, use the same exception handlers around
await client.list_templates().
File objects and in-memory binary streams can also be passed to extract().
The SDK leaves caller-owned streams open; inspect result.failed as in the
Quick Start.
Read Task Results
Use get_task_results() to read one page of completed documents, or
iter_task_results() to traverse all available pages. These methods return
current results immediately. While a task is processing, results may be empty
or partial; an empty page does not mean processing has finished.
from pathlib import Path
from suparse import SuparseClient
with SuparseClient() as client:
task_id = client.upload_file(Path("invoice.pdf"))
client.poll_task_status(task_id) # Wait if you need the complete result set.
for document in client.iter_task_results(task_id):
print(document.id, document.extraction_data)
page = client.get_task_results(task_id, limit=50)
if page.next_cursor is not None:
next_page = client.get_task_results(task_id, cursor=page.next_cursor, limit=50)limit and the iterator's page_size accept integers from 1 to 100 (default:
100). Each TaskResultPage contains documents and next_cursor; a null
cursor indicates the end of the available pages. Save a non-null cursor to
resume pagination. TaskResultDocument.extraction_data contains the extracted
fields, including nested JSON; page numbers are returned as supplied by the API.
With AsyncSuparseClient, await get_task_results() and use async for with
iter_task_results():
import asyncio
from suparse import AsyncSuparseClient
async def main():
async with AsyncSuparseClient() as client:
task_id = "your-task-id"
async for document in client.iter_task_results(task_id, page_size=50):
print(document.extraction_data)
asyncio.run(main())Export Processed Documents
Use document IDs from TaskExport.document_ids or poll_task_status() to export
previously processed documents:
from pathlib import Path
from suparse import ExcelLayout, ExportFormat, ExportType, SuparseClient
with SuparseClient() as client:
result = client.extract("invoice.pdf")
document_ids = [doc_id for group in result.succeeded for doc_id in group.document_ids]
if document_ids:
saved_path = client.download_results(
document_ids,
Path("invoices.xlsx"),
format=ExportFormat.XLSX,
export_type=ExportType.UNIFIED,
xlsx_layout=ExcelLayout.FLAT,
)
print(saved_path)
for failure in result.failed:
print(failure.file, failure.error)See Choose an Export Mode and XLSX Layout for column selection, layout examples, and CLI equivalents.
Choose a method based on how you want to consume the export:
| Method | Returns | Use for |
|---|---|---|
export_documents() / fetch_results() | ExportResult | Parsed JSON in .task_exports, CSV/XLSX bytes in .data, or Google Sheets details in .google_sheets_export |
download_results() | Saved path as str | Writing an export to a file |
download_documents() | FileExport | Exact attachment bytes in .data, with .filename, .content_type, and .is_zip metadata |
All four methods accept format, export_type, xlsx_layout, wait_timeout,
and idempotency_key as keyword arguments. download_results() also accepts an
output path. An omitted path uses the API filename or a generated fallback in
the current directory; an existing directory receives the export filename.
Advanced Developer Workflows
Use these sections when you need direct control over uploads, recovery after an uncertain request, or background export artifacts. For standard extraction, start with Quick Start and Export Processed Documents.
Low-Level API
For cases where you need file-based output or direct control over the upload/poll/download cycle:
from pathlib import Path
from suparse import ExportFormat, SuparseClient
with SuparseClient() as client:
# Upload a file and get back a task ID
task_id = client.upload_file(
Path("invoice.pdf"),
template_id="YOUR_TEMPLATE_ID",
split=False,
auto_approve=True, # Set to False to require human review in the Suparse UI
)
# Poll until processing completes (returns status + document IDs)
status, doc_ids = client.poll_task_status(task_id)
# Export results by document IDs to a JSON file. Omitting the output path
# uses the API filename or a timestamped fallback in the current directory.
saved_path = client.download_results(
doc_ids,
Path("output.json"),
)
# Fetch non-JSON exports in memory
csv_export = client.fetch_results(
doc_ids,
format=ExportFormat.CSV,
)
print(csv_export.filename, csv_export.content_type, csv_export.is_zip)
# Delete documents by ID
client.delete_documents(doc_ids)
# List available templates
templates = client.list_templates()
for t in templates:
print(f"{t.name} ({t.template_language})")The async client also provides process_document() for file output and
process_batch() for raw batch tuples. process_document() returns a success
boolean; process_batch() returns (succeeded, failed), where successful entries
are (Path, task_id, document_ids) and failures are (Path, task_id_or_none, exception).
Check these outcomes before continuing. Use extract() for the shared
BatchResult interface shown above.
For the async equivalent, await upload_file(), poll_task_status(),
download_results(), fetch_results(), delete_documents(), and
list_templates() inside async with AsyncSuparseClient().
Schema Creation Recovery
Before starting a run, retain the input filename, submission time (with time
zone), destination folder, and any existing upload_batch_id / source_upload_id.
Save the returned run_id immediately, as in the schema-creation example.
-
You have a run ID: call
get_quick_schema_creation(run_id)or runsuparse quick-create-status RUN_ID. Resume waiting withwait_for_quick_schema_creation(run_id); do not start another run. -
The start response was lost: the SDK and CLI have no activity-list method. Query the REST activity endpoint using the same API key and API base URL. For the default API URL:
curl --get 'https://api.suparse.com/api/v1/templates/quick-create' \ --header "X-API-Key: $SUPARSE_API_KEY" \ --data-urlencode 'limit=50'Compare each entry in
itemsbyfilename,created_at, and, when known,upload_batch_idandfolder_id. You can filter the request byupload_batch_idorfolder_id. Follow a non-nullnext_cursorby sending it as the next request'scursorquery parameter. Use a matching entry'srun_idwith the status command above.
Activity is scoped to the authenticated uploader and effective team. Fully successful runs are omitted, and failed/partial runs are visible only within their observation window. An empty list therefore does not prove that the request was rejected. Check the Suparse UI for the resulting documents and template. If you cannot identify the outcome, contact support with the retained filename, time, folder, source IDs, and error details before resubmitting. Do not send your API key or PDF password.
Detailed Upload Confirmations
upload_file() returns a task ID string. Use upload_file_detailed() when you
need the complete confirmation, including upload or replay metadata:
from pathlib import Path
from suparse import SuparseClient
with SuparseClient() as client:
confirmation = client.upload_file_detailed(
Path("invoice.pdf"),
)
print(confirmation.model_dump(mode="json"))For an existing upload batch, pass its upload_batch_id and source_upload_id
to upload_file_detailed(). Obtain these IDs from the workflow that created the
batch; this SDK does not provide methods to create upload batches.
Upload confirmations without both IDs are attempted once. A network failure or
5xx response raises SuparseUploadConfirmationUnknownError: the upload may
already have been accepted. Retain the exact upload_reference_id, filename,
submission time (with time zone), folder ID, and any batch/source IDs. With
extract() or extract_folder(), read the reference from
failure.upload_reference_id in result.failed.
The SDK and CLI have no lookup by upload reference. To find candidate documents, open the Suparse UI and search for the filename around the submission time, or query the REST document list using the same API key. For example, replace the filename and timestamp below (and the base URL if you use a custom API URL):
curl --get 'https://api.suparse.com/api/v1/documents/' \
--header "X-API-Key: $SUPARSE_API_KEY" \
--data-urlencode 'filename=invoice.pdf' \
--data-urlencode 'created_after=2026-10-15T09:00:00Z' \
--data-urlencode 'uploaded_by=me' \
--data-urlencode 'page=1' \
--data-urlencode 'items_per_page=100'Inspect all matching pages, checking creation time, folder/batch, and document
contents; filenames alone are not unique. Export confirmed processed document
IDs with suparse export DOCUMENT_ID. If no candidate can be reliably matched,
ask support to reconcile the upload using the saved
upload_reference_id and submission details before uploading again. An empty
search does not establish that confirmation failed.
When both IDs are supplied, the SDK uses the server's replay protection for bounded transient retries. A 503 response is surfaced without retry because the upload may already have been accepted.
Structured API Errors
SuparseAPIError and its subclasses expose status_code and the raw
response_body. Structured API errors also provide .code and .meta:
from suparse import SuparseAPIError, SuparseClient
with SuparseClient() as client:
try:
client.list_templates()
except SuparseAPIError as exc:
print(exc.status_code, exc.code, exc.meta, exc.response_body)Background Exports and Recovery
Export methods automatically wait when the API accepts an export as a
background job. wait_timeout defaults to 900 seconds and bounds the background
completion wait, including polling retries. It does not set a deadline for
submission or download; individual HTTP requests have separate timeouts.
The SDK generates a UUID idempotency key for each export submission and reuses
it for automatic submission retries. To retain the key before making a request,
pass your own UUID string as idempotency_key. Keep it with any reported job ID
so you can recover after a timeout or uncertain response. An idempotency key
does not guarantee exactly-once generation for immediate exports.
If the submission response was lost and you only have the key, repeat the same
export request with the same document IDs, format, export mode, layout, and
idempotency_key. For the CLI, rerun the original suparse export command with
its saved --idempotency-key. Retain the original request options alongside the
key so you can reproduce it. Once a job ID is available, resume that job using
the methods below.
Use get_export_job() to inspect a job, wait_for_export_job() to wait for
completion, and download_export_job() to save its artifact:
from pathlib import Path
from suparse import SuparseClient, SuparseExportError, SuparsePollingTimeoutError
export_job_id = "your-export-job-id" # Job ID reported by an earlier export.
output_dir = Path("exports")
output_dir.mkdir(parents=True, exist_ok=True)
with SuparseClient() as client:
job = client.get_export_job(export_job_id)
print(job.status)
try:
client.wait_for_export_job(export_job_id, wait_timeout=900)
saved_path = client.download_export_job(export_job_id, output_dir)
print(saved_path)
except SuparsePollingTimeoutError as exc:
print(exc.export_job_id, exc.last_status, exc.idempotency_key)
# Resume later with wait_for_export_job(exc.export_job_id).
except SuparseExportError as exc:
print(exc.reason, exc.code, exc.meta, exc.export_job_id)get_export_job() also returns failed jobs and jobs whose artifacts are no
longer available. Job counts describe document selection, generation, and
exclusions; they are not a progress percentage.
Artifact Downloads and Integrity
download_export_job() requires a completed job with an available artifact and
does not wait. It verifies the artifact's size and SHA-256 checksum before
publishing the file. It refuses to replace an existing file unless
overwrite=True. download_results() can replace an existing file. In-memory
export methods buffer the artifact in memory.
Timeouts, Cancellation, and Deferred Cleanup
A local timeout or cancellation does not cancel the server job. Export errors
include export_job_id, idempotency_key, and job when available.
For async cancellation, use get_export_recovery_context() to retrieve these
details through the exception's cause/context chain on all supported Python
versions. Retain the returned context to resume later, and propagate cancellation:
import asyncio
from suparse import get_export_recovery_context
try:
result = await export_task
except asyncio.CancelledError as exc:
recovery = get_export_recovery_context(exc)
if recovery is not None:
print(recovery.export_job_id, recovery.idempotency_key)
# Persist these values; resume by job ID when available.
# Before acceptance, only the idempotency key may be known.
raiseSuparsePollingTimeoutError also exposes last_status and
operation_may_be_running. If processing with cleanup=True leaves an export
running or its submission outcome uncertain, cleanup is deferred for the
affected source documents. Inspect or resume the export, then delete those
documents explicitly. For extract(), recovery identifiers appear in
FailedResult.error.
Export Failure Reasons and Format Limits
SuparseExportError.reason identifies the failure:
| Reason | Meaning |
|---|---|
job_failure | The export job failed |
artifact_unavailable | The artifact is unavailable or expired |
unsupported_state | The job is in a state the SDK cannot handle |
protocol_failure | The export response does not match the expected protocol |
storage_failure | The artifact could not be downloaded |
integrity_failure | The downloaded artifact's size or checksum does not match |
incompatible_artifact | The artifact cannot be used as the requested result type |
Parsed JSON exports require a JSON array matching list[TaskExport].
Incompatible background JSON or ZIP artifacts raise SuparseExportError;
the SDK does not unpack ZIPs. Use download_documents() or
download_export_job() when you need the original artifact bytes.
Google Sheets exports are supported for immediate API responses; background
Google Sheets jobs raise SuparseExportError with reason="incompatible_artifact".
SDK Reference
Constructor Parameters
Both SuparseClient and AsyncSuparseClient accept the same parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
api_url | str | SUPARSE_API_URL env var or https://api.suparse.com/api/v1/ | API base URL |
api_key | str | SUPARSE_API_KEY env var | Your API key (required) |
poll_interval | int | 5 | Seconds between polling attempts |
max_poll_attempts | int | 300 | Max polling attempts before timeout |
Result Objects
| Object | Properties | Description |
|---|---|---|
TaskExport | task_id, original_file, total_documents_extracted, documents, data, document_ids | Export group for a processed input; documents contains DocumentExport objects with credits_used, template_id, etc. |
FailedResult | file, error, upload_reference_id | File that failed during extraction |
BatchResult | succeeded, failed, total | Container for batch results; total counts inputs while succeeded contains returned task export groups |
ExportResult | format, content_type, filename, is_zip, data, task_exports, google_sheets_export | Low-level export result for JSON, CSV, XLSX, and Google Sheets |
QuickSchemaStartResult, QuickSchemaStatusResult, QuickSchemaTerminalResult | Unions of typed lifecycle models | Automatic schema-creation results; inspect .status and model-specific fields |
TaskResultPage | documents, next_cursor | One page of currently completed task results |
TaskResultDocument | id, file_name, extraction_data, page and template fields | Extracted document returned by task-result reads |
ExportJobRead | export_job_id, status, counts, artifact, error | Background export status and recovery details |
ExportJobArtifact | filename, content_type, size_bytes, checksum_sha256 | Downloadable artifact metadata |
FileExport | format, content_type, filename, is_zip, data | Exact attachment bytes from download_documents() |
Export Formats
| Format | Result | Notes |
|---|---|---|
json | TaskExport list | Default structured extraction result |
csv | Binary export bytes | Uses API filename when provided; may be a ZIP |
xlsx | Binary export bytes | Uses API filename when provided; may be a ZIP |
google_sheets | GoogleSheetsExport | Requires Google Sheets integration |
export_type selects the template columns as explained in
Choose an Export Mode and XLSX Layout.
It accepts unified or original. The CLI and parsed export methods
default to unified; download_documents() defaults to original. It affects
CSV, XLSX, and Google Sheets exports; parsed JSON returns task export groups.
xlsx_layout accepts ExcelLayout.STANDARD (the default) or ExcelLayout.FLAT. It only affects XLSX exports.
Exceptions
All exceptions inherit from SuparseError.
| Exception | Raised When |
|---|---|
SuparseError | Base exception for all SDK errors |
SuparseNetworkError | Network connection fails or times out |
SuparsePollingTimeoutError | Processing/schema polling exceeds its attempt limit, or a background export exceeds wait_timeout |
SuparseExportError | Background job, artifact download, integrity, or format failure; inspect .reason and recovery context |
SuparseProcessingError | Document fails to process on the server |
SuparseAPIError | Base for HTTP error responses (has status_code, response_body, code, meta) |
SuparseAuthError | 401/403 authentication or authorization error |
SuparseNotFoundError | 404 resource not found |
SuparseRateLimitError | 429 too many requests |
SuparseServerError | 5xx server error |
SuparseUploadConfirmationUnknownError | Upload confirmation outcome is unknown; inspect upload_reference_id before taking action |
SuparseSDKError | SDK fails to parse the API response into the expected data model |
extract() Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
files | str, Path, IO[bytes], or iterable of these | required | One or more files to process |
template_id | str | None | Template ID (auto-detect if omitted) |
split | bool | False | Auto-split multi-page documents |
auto_approve | bool | True | Set to False to require human review in the Suparse UI |
pdf_password | str | None | Password applied to every input encrypted PDF |
folder_id | str | None | Folder ID applied to every uploaded input |
cleanup | bool | False | Delete documents from server after extraction |
on_progress | callable | None | Called with each TaskExport or FailedResult as it completes |
extract_folder() Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
folder | str or Path | required | Directory to scan |
pattern | str | "*" | Glob pattern for file discovery (filtered by supported extensions) |
template_id | str | None | Template ID (auto-detect if omitted) |
split | bool | False | Auto-split multi-page documents |
auto_approve | bool | True | Set to False to require human review in the Suparse UI |
pdf_password | str | None | Password applied to every input encrypted PDF |
folder_id | str | None | Folder ID applied to every uploaded input |
cleanup | bool | False | Delete documents from server after extraction |
on_progress | callable | None | Called with each result as it completes |