myocr-client — Python SDK for myocr.app
Official Python client for the myocr.app API. Convert PDFs and images to structured Excel using myocr's OCR engine (invoice, receipt, bank statement, business card, generic tables, plain text).
Install
pip install myocr-client
Quick start
Get an API key at /account/api (signup required), then:
from myocr_client import MyOCRClient
client = MyOCRClient(api_key="sk_live_...")
# or set MYOCR_API_KEY in env
# Synchronous conversion (≤5MB, ≤10 pages, returns immediately)
result = client.convert("invoice.pdf", model="invoice")
result.save("invoice.xlsx")
print(result.pages_used, result.model, result.request_id)
Models
| Model | Output | Best for |
|---|---|---|
tables |
xlsx with generic tables | Any structured table |
text |
plain txt | OCR text extraction |
invoice |
xlsx with Vendor / Customer / Total / Line items | Invoices, bills |
receipt |
xlsx with Merchant / Date / Items / Total | Receipts |
bank_statement |
xlsx with Account / Transactions sheet | Bank statements |
business_card |
xlsx with Contact / Company / Phones / Emails | Business cards |
Async jobs (files > 5MB or > 10 pages)
job = client.create_job(
"annual_report.pdf",
model="bank_statement",
webhook_url="https://your.app/webhooks/myocr", # optional
)
# Option 1: polling with exponential backoff
job.wait(timeout=600)
job.download("report.xlsx")
# Option 2: notified via webhook (preferred for prod) — see "Webhook verification" below
Batch (1–20 files in one call)
result = client.batch(
["a.pdf", "b.pdf", "c.pdf"],
model="invoice",
webhook_url="https://your.app/webhooks/myocr",
)
print(result.jobs_created, "jobs queued;", len(result.errors), "errors")
# Wait for all and download
for job in result.wait_all(timeout=1200):
if job.is_done:
job.download(f"{job.request_id}.xlsx")
Webhook verification
myocr signs every webhook with HMAC-SHA256 (header X-MyOCR-Signature: sha256=<hex>). Always verify before trusting the payload — and use raw bytes, not the parsed JSON:
from flask import Flask, request
from myocr_client import verify_webhook_signature
app = Flask(__name__)
SECRET = "your-shared-secret" # same as server WEBHOOK_SIGNING_SECRET
@app.route("/webhooks/myocr", methods=["POST"])
def myocr_webhook():
body = request.get_data() # raw bytes, NOT request.get_json()
sig = request.headers.get("X-MyOCR-Signature", "")
if not verify_webhook_signature(body, sig, SECRET):
return "invalid signature", 401
event = request.get_json() # safe now
# {"event": "job.completed", "data": {"request_id": "...", "status": "done", ...}}
return "", 200
Events: job.completed, job.failed.
Retry policy: 1m → 5m → 30m → 2h (4 retries beyond the first attempt).
Error handling
Every error code maps to a typed exception:
from myocr_client import MyOCRClient, QuotaExceeded, InvalidApiKey, OcrEngineError
client = MyOCRClient(api_key="sk_live_...")
try:
result = client.convert("doc.pdf", model="invoice")
except QuotaExceeded as e:
print(f"Plan {e.current_plan}, used {e.calls_used}/{e.calls_limit}")
print(f"Upgrade: {e.upgrade_url}")
print(f"Resets: {e.reset_date}")
except InvalidApiKey:
print("Rotate your key from /account/api")
except OcrEngineError:
print("OCR engine upstream failure; safe to retry")
| Exception | HTTP | Code |
|---|---|---|
MissingApiKey |
401 | MISSING_API_KEY |
InvalidApiKey |
401 | INVALID_API_KEY |
UnsupportedModel |
400 | UNSUPPORTED_MODEL |
UnsupportedFileType |
400 | UNSUPPORTED_FILE_TYPE |
MissingFile |
400 | MISSING_FILE |
FileTooLarge |
413 | FILE_TOO_LARGE |
TooManyPages |
413 | TOO_MANY_PAGES |
InvalidWebhookUrl |
400 | INVALID_WEBHOOK_URL |
QuotaExceeded |
402 | QUOTA_EXCEEDED |
NotReady |
409 | NOT_READY |
NotFound |
404 | NOT_FOUND |
OcrEngineError |
502 | OCR_ERROR |
StorageError |
503 | STORAGE_ERROR |
RateLimited |
429 | — |
ServiceNotReady |
503 | SERVICE_NOT_READY |
InternalError |
500 | INTERNAL_ERROR |
The SDK automatically retries 429 and 5xx responses up to 3 times with exponential backoff (honoring Retry-After when present). After retries exhausted the exception is raised.
Input flexibility
client.convert() and client.create_job() accept:
- A file path:
client.convert("/path/to/doc.pdf", ...) - Raw bytes:
client.convert(pdf_bytes, filename="doc.pdf", ...) - A file-like object:
with open("doc.pdf", "rb") as f: client.convert(f, ...)
Configuration
| Argument | Env var | Default |
|---|---|---|
api_key |
MYOCR_API_KEY |
— (required) |
base_url |
MYOCR_BASE_URL |
https://api.myocr.app |
timeout |
— | 60s |
retry_attempts |
— | 3 |
session |
— | new requests.Session() |
For staging:
client = MyOCRClient(api_key="sk_test_...", base_url="https://beta.myocr.app")
Monitor your quota
Check current month usage programmatically (e.g. to upgrade before exhaustion):
usage = client.usage()
# {
# "plan": "free", "calls_used": 42, "calls_limit": 100,
# "percentage": 42.0, "reset_date": "2026-06-01T00:00:00",
# "year_month": "2026-05", "is_test_key": False
# }
if usage["percentage"] and usage["percentage"] > 80:
# alert ops, upgrade plan, or stop background workers
...
Status & limits
status = client.status()
# {
# "service": "myocr.app API", "version": "v1",
# "models_supported": ["bank_statement", "business_card", ...],
# "features": {"sync_convert": True, "async_jobs": True, "webhook": True, ...},
# "limits": {"sync_max_bytes": 5242880, "sync_max_pages": 10,
# "jobs_max_bytes": 52428800, "sync_rate_per_minute": 60,
# "jobs_rate_per_minute": 120}
# }
Rate limits (server-side)
| Endpoint | Limit |
|---|---|
POST /v1/convert |
60 / min |
POST /v1/jobs |
120 / min |
POST /v1/batch |
30 / min |
The SDK handles 429 with automatic retry. If you saturate the quota, upgrade your plan from the dashboard.
Reference
- Full OpenAPI spec: openapi.yaml
- Interactive docs: /docs/api (Scalar UI)
- Dashboard: /account/api — manage keys, view usage, upgrade
- Webhook signing secret: generated when you create a webhook integration; shared via dashboard.
Development
git clone https://github.com/Selaf688/myocr-3.5
cd myocr-3.5/sdk/python
pip install -e ".[dev]"
pytest -v
Versioning
Semantic versioning. The API itself is v1 and stable; the SDK can release patch/minor independently.
License
MIT. See LICENSE.
Support
- Documentation: https://www.myocr.app/docs/api
- Email: info@myocr.app
- Issues: https://github.com/Selaf688/myocr-3.5/issues
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file myocr_client-0.2.0.tar.gz.
File metadata
- Download URL: myocr_client-0.2.0.tar.gz
- Upload date:
- Size: 17.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ef5fa7e4569fdcb07579c4138334593ccbb7aef58d610796b06b795990f75bb
|
|
| MD5 |
46f52502896f979894e5de9c2e1b2307
|
|
| BLAKE2b-256 |
c03e97a4d0d31bfc044cdd87cd0545cbc590c1019d1a05ab01213fcac38184c9
|
File details
Details for the file myocr_client-0.2.0-py3-none-any.whl.
File metadata
- Download URL: myocr_client-0.2.0-py3-none-any.whl
- Upload date:
- Size: 16.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a80aeb0e3b0b1aed4381250f6520665b2a3b1feb5350ca4243e3c3e32cdc479c
|
|
| MD5 |
d4df8f6614ac58893801c39e4e9d2020
|
|
| BLAKE2b-256 |
de0092cce684f0066f739ade3db6570f75e62e605d7c1176d809df501f9ac0c5
|