Metadata-Version: 2.5
Name: myocr-client
Version: 0.2.0
Summary: Official Python SDK for myocr.app — convert PDFs and images to structured Excel using myocr's OCR engine.
Project-URL: Homepage, https://www.myocr.app
Project-URL: Documentation, https://www.myocr.app/docs/api
Project-URL: Repository, https://github.com/Selaf688/myocr-3.5
Project-URL: Bug Tracker, https://github.com/Selaf688/myocr-3.5/issues
Project-URL: Changelog, https://github.com/Selaf688/myocr-3.5/blob/main/sdk/python/CHANGELOG.md
Author-email: "MAD.AI SRL" <info@myocr.app>
License: MIT
License-File: LICENSE
Keywords: api-client,document-extraction,excel,myocr,ocr,pdf
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Office Suites
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Requires-Dist: requests>=2.28
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: responses>=0.23; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Description-Content-Type: text/markdown

# myocr-client — Python SDK for myocr.app

Official Python client for the **[myocr.app](https://www.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).

[![PyPI version](https://img.shields.io/pypi/v/myocr-client.svg)](https://pypi.org/project/myocr-client/)
[![Python versions](https://img.shields.io/pypi/pyversions/myocr-client.svg)](https://pypi.org/project/myocr-client/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

---

## Install

```bash
pip install myocr-client
```

## Quick start

Get an API key at [/account/api](https://www.myocr.app/account/api) (signup required), then:

```python
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)

```python
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)

```python
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:

```python
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:

```python
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:

```python
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):

```python
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

```python
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](https://www.myocr.app/static/openapi.yaml)
- **Interactive docs:** [/docs/api](https://www.myocr.app/docs/api) (Scalar UI)
- **Dashboard:** [/account/api](https://www.myocr.app/account/api) — manage keys, view usage, upgrade
- **Webhook signing secret:** generated when you create a webhook integration; shared via dashboard.

## Development

```bash
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](./LICENSE).

## Support

- Documentation: <https://www.myocr.app/docs/api>
- Email: info@myocr.app
- Issues: <https://github.com/Selaf688/myocr-3.5/issues>
