Skip to main content

LocalParse — Python client

Official Python client for the LocalParse API. LocalParse gives you two products under one API:

  1. Parse — turn any document into clean Markdown, JSON, or text. Drop-in LlamaParse-compatible, plus a deterministic accuracy layer: table-detection recovery (catches tables a layout model misses) and oracle-free financial-identity checks (flags Totals that don't reconcile).
  2. Extract (Beta) — pull structured JSON out of parsed documents using your own JSON Schema. Server-side schema validation guarantees the returned object matches.

Install

pip install localparse

Quickstart — Parse

from localparse import LocalParse

client = LocalParse(api_key="lp-...")          # or set LOCALPARSE_API_KEY

result = client.parse("invoice.pdf", result_type="markdown")
print(result.markdown)

# Accuracy signal that plain OCR/LLM parsers don't give you:
print(result.identity_check)     # {tables_checked, violations, ...} or None
print(result.recovered_tables)   # tables recovered by detect_repair

Fetch JSON or the ingestion-ready structured contract instead:

result = client.parse("10k.pdf", result_type="json")
for page in result.pages:
    ...

structured = client.parse("10k.pdf", result_type="structured")

Quickstart — Extract (Beta)

Parse first to get clean markdown, then extract the fields you actually care about:

md = client.parse("invoice.pdf").markdown

invoice = client.extract(md, {
    "type": "object",
    "properties": {
        "vendor":     {"type": "string"},
        "invoice_no": {"type": "string"},
        "total":      {"type": "number"},
        "due_on":     {"type": "string", "description": "ISO 8601 date"},
    },
    "required": ["vendor", "total"],
})

print(invoice["vendor"], invoice["total"])

The server validates the model's output against your schema before returning: a non-conforming response surfaces as SchemaConformanceError rather than as silently broken data. Pre-flight safety failures (bad schema shape, depth/width caps, external $ref) surface as SchemaValidationError.

Webhooks (skip polling)

Pass webhook_url to either Parse or Extract and our worker POSTs a signed event the moment the job finishes — Stripe-shape HMAC-SHA256 so you can verify it came from us. One signing secret covers both products.

# Parse — fires parse.succeeded / parse.failed
client.upload(
    "report.pdf",
    webhook_url="https://yourapp.com/localparse/webhook",
)

# Extract — fires extract.succeeded / extract.failed
client.submit_extract(
    md,
    schema,
    webhook_url="https://yourapp.com/localparse/webhook",
)

Parse events are notifications (the full markdown / JSON can be many MB, so we don't inline it) — fetch the payload with client.get_result(job_id) once the event arrives. Extract events carry the schema-conformant data directly.

Grab your signing secret from Account → Webhooks in the dashboard (one per account, rotatable), then verify inbound requests with the bundled helper:

from localparse import verify_webhook, InvalidWebhookSignature

@app.post("/localparse/webhook")
def receive(request):
    try:
        event = verify_webhook(
            body             = request.body,                          # raw bytes
            signature_header = request.headers["X-LocalParse-Signature"],
            secret           = os.environ["LOCALPARSE_WEBHOOK_SECRET"],
        )
    except InvalidWebhookSignature:
        return 400

    if event["event"] == "extract.succeeded":
        ingest(event["data"])
    elif event["event"] == "parse.succeeded":
        # Notification only — fetch the result yourself:
        result = client.get_result(event["id"], "markdown")
        ingest_markdown(result.markdown)
    else:
        log_failure(event["id"], event["error_message"])
    return 200

verify_webhook rejects modified bodies, bad signatures, missing headers, and timestamps older than 5 minutes (replay protection). Webhook URLs must be https and must not resolve to private/loopback IPs (SSRF guard runs at submit-time).

Retry policy: first attempt is inline, then 10s → 60s → 300s → 1800s (5 total) before the delivery is marked failed in the Jobs dashboard.

Persist a whole folder (incremental)

Ingest a data room into a named case; re-runs only parse new/changed files (unchanged files are skipped by content hash):

results = client.parse_folder(
    "./data-room",
    case_id="acme",
    resume=True,
    on_progress=lambda path, res: print("parsed" if res else "skipped", path),
)

Full control (async jobs)

job = client.upload("big.pdf", result_type="json", case_id="acme")
job = client.wait(job.id)
if job.is_success:
    result = client.get_result(job.id, "json")

Configuration

Argument Default Meaning
api_key LOCALPARSE_API_KEY env Bearer token for the API.
base_url https://api.localparse.com Point at a self-hosted instance if needed.
timeout 60 Per-request HTTP timeout (seconds).
poll_interval 2.0 Seconds between status polls in parse/wait.
max_wait 900 Max seconds to wait for a job before JobTimeoutError.

Errors

AuthenticationError (401/403), QuotaExceededError (402), NotFoundError (404), RateLimitError (429, with .retry_after), APIError (other non-2xx), JobFailedError (job ended ERROR/CANCELED), JobTimeoutError, SchemaValidationError (400 — bad data_schema), SchemaConformanceError (422 — model output didn't match the schema) — all subclass LocalParseError.

Metadata

Release files for localparse 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for localparse 0.5.0
File Size Uploaded
localparse-0.5.0.tar.gz 19.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for localparse 0.5.0
File Interpreter ABI Platform
localparse-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 37.3 kB

Release files / localparse-0.5.0.tar.gz

Download URL localparse-0.5.0.tar.gz
Size 19.6 kB
Tags Source
SHA-256 checksum
How to use checksums
4781f6c6b6f109b49d8b764dbb839dbe98358dcc3c3b04dcdc5c4e195234e6a0
BLAKE2b-256 checksum
How to use checksums
679c5ac575181ee0686f661be87a59dd657abe2ea90f85f0ccdb439110c60e7f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / localparse-0.5.0-py3-none-any.whl

Download URL localparse-0.5.0-py3-none-any.whl
Size 17.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
778ed97264c2269648eb44c6107e9fc30c13460215433653f5f92ca678551241
BLAKE2b-256 checksum
How to use checksums
aa7435831458974a38dc192f1d9fcd599bcbda84518e1f994688048305cdd92a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page