Início Blog Como converter 100 faturas em 10 minutos com Python (tutorial SDK myocr) 2026-05-26 11 min de leitura Como converter 100 faturas em 10 minutos com Python (tutorial SDK myocr) Do zero a um pipeline batch funcional com o SDK oficial myocr-client. Código real, tratamento de erros real, entrega via webhook. Por equipe myocr.app 100 faturas PDF → 100 arquivos Excel estruturados em menos de 10 minutos com 30 linhas de Python Por que um SDK Python dedicado importa Se você vai colocar OCR em produção em Python, tem três opções. Pode chamar a API com requests cru e escrever todo o boilerplate — autenticação, retries, mapeamento de erros, polling para jobs async, downloads de signed URL. Pode usar um gerador OpenAPI que produz um cliente funcional mas pouco ergonômico. Ou pode instalar um SDK mantido que abstrai o protocolo e deixa você escrever apenas código de negócio. Este tutorial usa a terceira via: myocr-client, o SDK oficial Python do myocr.app. Em 11 minutos você sai do pip install a um script que converte 100 faturas PDF em paralelo, gerencia com elegância quota esgotada e erros OCR, e notifica seu app via webhook quando cada job termina. O que você vai construir Um único script Python que: Lê uma pasta de faturas PDF (misturando digitais e escaneadas) Submete como jobs async via /v1/batch Faz polling ou recebe notificações webhook quando cada job termina Baixa arquivos Excel estruturados (Fornecedor, Cliente, Itens, Total, IVA) Recupera de quota esgotada, blips de rede e erros OCR por arquivo sem crashar Total: ~30 linhas de código de negócio, mais um receptor de webhook se quiser entrega push. Pré-requisitos Python 3.8+ Uma API key de myocr.app/account/api (tier grátis: 100 chamadas/mês, sem cartão) Uma pasta de faturas PDF de teste — ou use as fixtures de exemplo no repo do SDK Passo 1: instalar pip install myocr-client É tudo. O SDK depende apenas de requests. Sem extensões nativas, sem runtime específico do SDK. Passo 2: converta sua primeira fatura (sync) from myocr_client import MyOCRClient client = MyOCRClient(api_key="sk_live_...") # ou defina MYOCR_API_KEY env var result = client.convert("fatura.pdf", model="invoice") result.save("fatura.xlsx") print(f"{result.pages_used} páginas → fatura.xlsx ({result.request_id})") Essa é uma chamada OCR completa. O método convert() é síncrono e melhor para arquivos abaixo de 5 MB e 10 páginas. O ConversionResult retornado inclui content (bytes), pages_used, o model original e um request_id que você pode grep nos logs do servidor. Passo 3: mude para async para processamento batch Para 100 faturas você não quer 100 chamadas sync sequenciais — é latência serial. Use /v1/batch. O SDK expõe como client.batch(): from pathlib import Path from myocr_client import MyOCRClient client = MyOCRClient() # MYOCR_API_KEY do env folder = Path("./faturas") pdfs = sorted(folder.glob("*.pdf"))[:20] # /v1/batch aceita até 20 arquivos batch = client.batch([str(p) for p in pdfs], model="invoice") print(f"Criados {batch.jobs_created} jobs, {len(batch.errors)} erros") done = batch.wait_all(timeout=600) for job in done: if job.is_done: job.download(f"out/{job.request_id}.xlsx") else: print(f"Falhou: {job.request_id} — {job.error_detail}") Três coisas a notar. Primeiro, o endpoint /v1/batch aceita no máximo 20 arquivos por chamada — para 100 faturas, divida a pasta em 5 batches. Segundo, wait_all() faz polling de cada job individualmente com backoff exponencial (1s → 2s → 4s → 8s → 15s cap), então 100 chamadas sleep(1) não queimam seu rate limit. Terceiro, se um único arquivo falhar a extração OCR, apenas aquele Job termina em failed — os outros completam normalmente. Passo 4: processe 100 faturas em 5 chunks from pathlib import Path from myocr_client import MyOCRClient client = MyOCRClient() folder = Path("./faturas") all_pdfs = sorted(folder.glob("*.pdf")) CHUNK = 20 out_dir = Path("./out"); out_dir.mkdir(exist_ok=True) for i in range(0, len(all_pdfs), CHUNK): chunk = all_pdfs[i:i + CHUNK] print(f"\nBatch {i // CHUNK + 1}: {len(chunk)} arquivos") batch = client.batch([str(p) for p in chunk], model="invoice") for job in batch.wait_all(timeout=900): target = out_dir / f"{job.request_id}.xlsx" if job.is_done: job.download(str(target)) print(f" ✓ {target.name} ({job.pages_used} páginas)") else: print(f" ✗ {job.request_id}: {job.error_detail}") print("\nFeito.") Tempo total numa key do tier grátis com concorrência padrão: aproximadamente 8-10 minutos para 100 faturas, dominado pela latência do processamento OCR, não pelo seu código. Em planos pagos com maior concorrência, o mesmo workload termina em 3-5 minutos. Passo 5: tratamento de erros como adulto O SDK mapeia cada código de erro da API para uma exceção tipada. Codifique defensivamente: from myocr_client import ( MyOCRClient, QuotaExceeded, OcrEngineError, RateLimited, InvalidApiKey, FileTooLarge, ) client = MyOCRClient() try: result = client.convert("fatura.pdf", model="invoice") except QuotaExceeded as e: print(f"Plano {e.current_plan}: {e.calls_used}/{e.calls_limit} chamadas usadas") print(f"Upgrade em {e.upgrade_url}, reseta {e.reset_date}") except FileTooLarge: print("Use create_job() em vez de convert() — mude para o path async") except OcrEngineError: pass # upstream OCR falhou, seguro tentar de novo após 30s except RateLimited: pass # raro: o SDK tenta 429 automaticamente até 3 vezes except InvalidApiKey: raise SystemExit("Rotacione sua API key — a atual não é válida") O retry automático em respostas 429 e 5xx (respeitando Retry-After) é a vitória ergonômica mais comum comparado com escrever código requests cru. Te salva do típico incidente em produção "esqueci de tratar a rede instável". Passo 6: mude para webhooks (zero polling) Polling funciona mas é ruidoso. Se você tem um endpoint HTTP exponível publicamente, a entrega via webhook é mais limpa. Passe webhook_url ao criar jobs: batch = client.batch( pdfs, model="invoice", webhook_url="https://meuapp.com/webhooks/myocr", ) # Sem esperar — seu endpoint receberá um POST por job No lado receptor (exemplo Flask): from flask import Flask, request from myocr_client import verify_webhook_signature app = Flask(__name__) SECRET = "seu-secret-compartilhado" @app.route("/webhooks/myocr", methods=["POST"]) def myocr_webhook(): body = request.get_data() # IMPORTANTE: bytes crus, não request.get_json() sig = request.headers.get("X-MyOCR-Signature", "") if not verify_webhook_signature(body, sig, SECRET): return "assinatura inválida", 401 event = request.get_json() request_id = event["data"]["request_id"] if event["event"] == "job.completed": ... # baixa result_url, atualiza DB, notifica usuário elif event["event"] == "job.failed": ... # logue error_detail, retry ou alerte ops return "", 200 Duas coisas não óbvias: (1) verifique a assinatura sobre bytes crus — se você serializar o JSON parseado de volta para string, a assinatura não vai bater por causa de whitespace e ordem das chaves; (2) os webhooks têm política de retry automática do lado servidor (1m → 5m → 30m → 2h), então não se preocupe se seu endpoint ficou fora brevemente. Passo 7: escolha o modelo certo O SDK expõe os mesmos seis modelos prebuilt que a API REST oferece. Escolha o mais específico para seu tipo de documento: invoice — faturas de fornecedor, itens, totais, IVA. O que este tutorial usa. receipt — recibos POS, comerciante, itens, total. Bom para relatórios de despesa. bank_statement — transações, datas, débito/crédito, saldo corrente. business_card — contato, empresa, telefones, emails, endereços. tables — extração de tabelas genérica para documentos sem modelo especializado. text — texto OCR plano, sem estrutura. Usar um modelo especializado é a diferença entre obter uma tabela desestruturada que precisa de limpeza e obter Fornecedor / Total / Itens já parseados em colunas Excel tipadas. Passo 8: checklist de produção Antes de enviar isso para um workload real: Use keys sk_test_* em dev — são rate-limited mas não consomem sua quota faturável Defina MYOCR_API_KEY via env var, nunca hardcoded — o SDK lê automaticamente Configure seu secret manager para o webhook signing secret em ambos os lados (servidor myocr e seu receptor) Logue request_id em cada chamada para correlacionar com logs do servidor se abrir um ticket de suporte Defina um timeout sensato em Job.wait() — o default 600s vai bem para faturas, suba para extratos bancários com 50+ páginas Monitore QuotaExceeded no seu error tracker — é o sinal para fazer upgrade do plano antes que morda Onde ir depois A referência completa da API está em Scalar UI com exemplos copy-paste para cada endpoint. O código fonte do SDK é open source no GitHub — leia client.py se quiser estendê-lo, ou abra um issue se encontrar uma feature faltando. Se você está integrando num SaaS que precisa de OCR, o SDK é também o path recomendado para nossas integrações Zapier, QuickBooks e Xero (todas usam internamente). Resumo em uma tela # pip install myocr-client import os from myocr_client import MyOCRClient, QuotaExceeded client = MyOCRClient() # MYOCR_API_KEY env var # Sync (≤5MB, ≤10 páginas): client.convert("doc.pdf", model="invoice").save("out.xlsx") # Async + batch (≤20 arquivos/chamada, ≤50MB cada): batch = client.batch( ["a.pdf", "b.pdf", "c.pdf"], model="invoice", webhook_url="https://meuapp.com/webhooks/myocr", ) for job in batch.wait_all(timeout=600): if job.is_done: job.download(f"out/{job.request_id}.xlsx") Mesmo padrão em Node.js / TypeScript Prefere JavaScript? O SDK Node myocr-client tem a mesma superfície, mesmos nomes de método (camelCase), exceções tipadas, zero dependências runtime (Node 18+ usa fetch / FormData / crypto nativos). // npm install myocr-client import { MyOCRClient } from 'myocr-client'; const client = new MyOCRClient(); // MYOCR_API_KEY do env // Sync: const r = await client.convert('fatura.pdf', { model: 'invoice' }); await r.save('fatura.xlsx'); // Async + batch: const batch = await client.batch(['a.pdf', 'b.pdf', 'c.pdf'], { model: 'invoice' }); const done = await batch.waitAll({ timeoutMs: 600_000 }); for (const job of done) { if (job.isDone) await job.download(`out/${job.requestId}.xlsx`); } Mesma API por trás, mesmos códigos de erro (mapeados em classes TS), mesma entrega de webhook e verificação de assinatura. Escolha a linguagem que encaixa no seu stack. Experimente hoje: obtenha uma API key grátis em myocr.app/account/api (sem cartão), pip install myocr-client (ou npm install myocr-client) e processe seu primeiro batch em 5 minutos. Obtenha sua API key e SDK em 30 segundos Tier grátis: 100 conversões por mês, todos os 6 modelos prebuilt, sem cartão. pip install myocr-client e envie OCR esta tarde. Obter API key (grátis)