PDF to Markdown
Servidor MCP hospedado que converte PDFs em Markdown limpo e pronto para LLMs, com tabelas, fórmulas (LaTeX) e OCR. Motores próprios (MinerU + Docling), não um wrapper de LLM.
Documentação
Duas superfícies, um mesmo motor
Escolha a integração que melhor se encaixa. Ambas usam o mesmo motor de conversão e obedecem aos mesmos slots, limites e retenção.
API REST
Endpoints HTTPS com chave de API do tipo bearer. DTOs estáveis, erros previsíveis, criação idempotente.
MCP hospedado
Um endpoint gerenciado do Model Context Protocol que expõe a conversão como ferramentas de agente – um wrapper fino sobre a mesma API.
Ações Custom GPT
Importe uma especificação OpenAPI reduzida em um ChatGPT Custom GPT para que ele converta PDFs como uma ferramenta integrada.
Chaves de API bearer via HTTPS
A API e o MCP usam chaves de API bearer – distintas do caminho assinado por dispositivo que a extensão do Chrome usa. Uma conta gratuita do Google é necessária para gerar chaves.
Obter uma chave
- Entre com o Google (conta gratuita).
- Gere uma chave de API na sua conta; ela é exibida apenas uma vez.
- Envie-a como
Authorization: Bearer p2m_…em cada requisição. - Chaves são segredos: armazene-as no servidor, rotacione e revogue a qualquer momento.
Padrões honestos
Chaves, não senhas. A extensão permanece anônima e assinada por dispositivo; as chaves de API/MCP são uma credencial separada, vinculada à conta.
Somente HTTPS. Sempre envie chaves via TLS; nunca incorpore uma chave em código do lado do cliente enviado aos usuários.
Criação idempotente. Um Idempotency-Key opcional na criação permite tentar novamente com segurança, sem jobs duplicados.
Escopos. Cada chave de API carrega escopos: jobs:create, jobs:read, jobs:download, jobs:delete (os padrões), além de settings:read / settings:write. Emita chaves com privilégio mínimo; a API REST e as ferramentas MCP aplicam os escopos da chave.
Criar um job, aguardar, buscar Markdown, limpar o slot
Um ciclo de vida previsível, duas formas de conduzi-lo: chame a API REST do seu próprio código ou use as ferramentas equivalentes do MCP hospedado. Nunca reivindique um resultado antes de status=ready.
API REST MCP hospedado
1
Criar o job
Envie por POST uma URL de PDF ou bytes de upload. Receba de volta um id de job e um slot. Idempotency-Key é respeitado, mas opcional.
POST /api/v2/jobsmcp · pdf_to_markdown_create_job_from_url
2
Verificar o status
Consulte o job até ready ou error, ou registre um webhook assinado nos planos pagos em vez de consultar.
GET /api/v2/jobs/{id}mcp · pdf_to_markdown_get_job
3
Buscar o Markdown
Baixe o resultado assim que estiver pronto. Leia truncated e pages para saber se um documento longo foi retornado parcialmente.
GET /api/v2/jobs/{id}/downloadmcp · pdf_to_markdown_get_markdown
4
Excluir / limpar o slot
Libere um slot quando terminar. Excluir jobs na fila ou em processamento é destrutivo – confirme em clientes voltados ao usuário.
DELETE /api/v2/jobs/{id}mcp · pdf_to_markdown_delete_job
# 1. create a job from a PDF URL
curl -X POST https://pdf2md.dev/api/v2/jobs \
-H "Authorization: Bearer p2m_…" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/report.pdf"}'
# → { "job_id": "job_9f3c…", "status": "queued" }
# 2. poll status
curl https://pdf2md.dev/api/v2/jobs/job_9f3c… \
-H "Authorization: Bearer p2m_…"
# → { "status": "ready", "pages": 24, "truncated": false }
# 3. fetch the Markdown
curl https://pdf2md.dev/api/v2/jobs/job_9f3c…/download \
-H "Authorization: Bearer p2m_…"
# 4. free the slot
curl -X DELETE https://pdf2md.dev/api/v2/jobs/job_9f3c… \
-H "Authorization: Bearer p2m_…"
Erros. As respostas usam formatos estáveis e códigos HTTP previsíveis (400 entrada inválida, 401 autenticação, 404 job desconhecido, 409 sem slot livre / slots_full, 413 grande demais, 429 limite de taxa excedido). O esquema completo está na especificação OpenAPI.
Mais endpoints de job
Criar a partir de arquivo (multipart) POST /api/v2/jobs
Listar seus jobs GET /api/v2/jobs
Criação em lote (pago) POST /api/v2/jobs/batch
A criação aceita um url JSON ou um file multipart, além de file_name, external_id, tags e callback_url / callback_secret opcionais para um webhook por job. A criação em lote é tudo-ou-nada e deve caber nos seus slots livres.
O objeto de job
job_id string
status queued · processing · ready · error
pages · output_size inteiro
truncated booleano
error_code · error_message motivo (quando houver erro)
download_url string (quando pronto)
external_id · tags seus metadados
slot_usage · tier contexto de cota
Conta e uso. Verifique seu tier, limites e uso em tempo de execução com GET /api/v2/me, /api/v2/limits e /api/v2/usage; gerencie chaves em /api/v2/api-keys e webhooks em /api/v2/webhooks.
Converter um PDF para Markdown em Python
As mesmas quatro chamadas em qualquer linguagem. Aqui está com requests. Para um passo a passo completo com tratamento de erros, veja o tutorial em Python.
# pip install requests
import time, requests
API = "https://pdf2md.dev/api/v2"
H = {"Authorization": "Bearer p2m_…"}
# 1. create a job from a PDF URL (or post a file with files={"file": ...})
job = requests.post(f"{API}/jobs", headers=H,
json={"url": "https://example.com/report.pdf"}).json()
jid = job["job_id"]
# 2. poll until ready (or register a webhook instead)
while True:
j = requests.get(f"{API}/jobs/{jid}", headers=H).json()
if j["status"] in ("ready", "error"):
break
time.sleep(3)
# 3. download the Markdown
md = requests.get(f"{API}/jobs/{jid}/download", headers=H).text
print(md)
Mais receitas: upload de arquivo e Node
Criar a partir de um arquivo local (curl)
# multipart upload of a local PDF
curl -X POST https://pdf2md.dev/api/v2/jobs \
-H "Authorization: Bearer p2m_…" \
-F "[email protected]" \
-F "file_name=document.pdf"
Node 18+ (fetch global)
// create from URL, poll, download
const API = "https://pdf2md.dev/api/v2";
const H = { Authorization: "Bearer p2m_…" };
let job = await (await fetch(\`${API}/jobs\`, {
method: "POST",
headers: { ...H, "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://example.com/report.pdf" })
})).json();
while (job.status === "queued" || job.status === "processing") {
await new Promise(s => setTimeout(s, 2000));
job = await (await fetch(\`${API}/jobs/${job.job_id}\`, { headers: H })).json();
}
if (job.status === "ready") {
const md = await (await fetch(\`${API}/jobs/${job.job_id}/download\`, { headers: H })).text();
console.log(md);
}
A verificação de assinatura de webhook está na seção Webhooks; a configuração do cliente MCP está na seção MCP. Esquema completo: OpenAPI.
Conversão como ferramentas de agente
Conecte um agente compatível ao nosso endpoint MCP gerenciado. As ferramentas são um wrapper fino sobre a API REST, então cada chamada obedece aos mesmos slots, limites e retenção.
1
Apontar o agente para o endpoint
JSON-RPC 2.0 sobre Streamable HTTP com sua chave de API como token bearer. Sem servidor local para executar. Métodos: initialize, tools/list, tools/call, ping.
POST https://pdf2md.dev/api/v2/mcp
2
Chamar as ferramentas
O mesmo ciclo de vida, além de limites, exposto como sete ferramentas. Cada uma respeita os escopos da chave; respostas de tools/call incluem slot_usage e tier.
create_job_from_url · create_job_from_upload (jobs:create) list_jobs · get_job (jobs:read) get_markdown (jobs:download) · delete_job (jobs:delete) get_limits
3
Respeitar as regras
Aguarde ready antes de usar a saída; confirme antes de excluir jobs na fila/em processamento; trate truncated e 429 Retry-After. (Os nomes das ferramentas são prefixados com pdf_to_markdown_.)
// MCP client config (hosted, no local process)
{
"mcpServers": {
"pdf2md": {
"url": "https://pdf2md.dev/api/v2/mcp",
"headers": {
"Authorization": "Bearer p2m_…"
}
}
}
}
Importar a especificação, obter uma ferramenta integrada
Publicamos duas especificações: a OpenAPI completa para desenvolvedores e uma especificação de ação reduzida com o subconjunto seguro e mínimo para clientes de IA e ChatGPT Custom GPT Actions.
OpenAPI completa
O contrato completo: todos os endpoints, parâmetros, DTOs e erros. Gere clientes ou explore em suas ferramentas.
Abrir a especificação completa
Especificação reduzida para Custom GPT
Um subconjunto mínimo de ações (criar, status, buscar) para ChatGPT Custom GPT Actions. Importe a URL, defina sua chave de API como autenticação, e seu GPT converte PDFs nativamente.
Abrir a especificação reduzida
A especificação reduzida é uma conveniência para clientes de IA, não um limite de segurança – as mesmas autenticação, escopos e limites se aplicam como na API completa.
Limites por tier, aplicados igualmente à API e ao MCP
Os limites vêm do seu tier e se aplicam de forma idêntica em todas as superfícies. Valores atualizados estão na página de preços.
Tier gratuito (com conta)
Slots ativos (profundidade da fila) 3
Tamanho máximo do PDF 10 MB
Orçamento de tempo por documento 15 min
Retenção do resultado pronto 1 hora
Tiers pagos aumentam slots, tamanho de arquivo, orçamento de tempo, retenção e limites de taxa, e adicionam webhooks e criação em lote. Comparar planos →
Limites de taxa e backpressure
Limites de taxa por tier. As requisições são limitadas por chave; se exceder, você recebe 429 com um cabeçalho Retry-After – recue e tente novamente.
Pressão de slots. Se todos os slots estiverem ocupados, a criação retorna 409. Libere um slot com delete ou aguarde um job terminar.
Prioridade no pago. Jobs pagos são executados com prioridade maior na fila em um pool de conversão pago dedicado, para não ficarem atrás do backlog gratuito.
Receba notificações em vez de consultar
Nos tiers pagos, registre um webhook assinado (ou passe um callback_url por job) e enviamos um POST para você em cada evento terminal notável: job.ready, job.error, job.truncated e job.deleted. O evento é uma notificação, não uma entrega: ele não carrega conteúdo do documento, então busque o Markdown pela API após recebê-lo.
1
2
Receber o evento
Enviamos um POST JSON com cabeçalhos X-P2M-Event, X-P2M-Timestamp, X-P2M-Delivery e X-P2M-Signature.
3
Verificar e agir
Recalcule a assinatura, confirme com 2xx e seja idempotente (as entregas podem tentar novamente com backoff). Depois, baixe o Markdown.
# delivery → your endpoint
X-P2M-Event: job.ready
X-P2M-Timestamp: 1718900000
X-P2M-Signature: sha256=9a8b7c…
{
"event": "job.ready",
"job": {
"job_id": "job_9f3c…",
"status": "ready",
"pages": 24, "truncated": false,
"download_url": "/api/v2/jobs/job_9f3c…/download"
}
}
# verify (Python): signature = sha256= + hex(HMAC(secret, "ts.rawbody"))
import hmac, hashlib
def verify(secret, ts, raw_body, sig):
expected = "sha256=" + hmac.new(
secret.encode(), f"{ts}.".encode() + raw_body,
hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig)
Instruções portáveis para agentes
Inclua estas regras no prompt de sistema de um agente para que ele use as ferramentas corretamente e nunca invente resultados.
Aguardar o pronto
Nunca reivindique ou resuma um resultado antes de status=ready. Enquanto queued ou processing, continue consultando ou aguarde o webhook.
Confirmar exclusões
Excluir um job queued ou processing é destrutivo. Pergunte ao usuário antes de chamar pdf_to_markdown_delete_job em um job não finalizado.
Tratar truncamento
Se truncated=true, informe ao usuário que o documento foi retornado parcialmente até o orçamento de tempo do tier e ofereça um tier superior ou dividir o arquivo.
Respeitar 429
Em 429, aguarde Retry-After segundos antes de tentar novamente. Não sobrecarregue a fila.
Limpar slots
Exclua jobs finalizados que você não precisa mais para não esgotar seus slots.
Ler a descoberta
Comece por /llms.txt e pela especificação OpenAPI em vez de adivinhar endpoints a partir do texto.