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.

Veja o ciclo de vida

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.

Conectar MCP

Ações Custom GPT

Importe uma especificação OpenAPI reduzida em um ChatGPT Custom GPT para que ele converta PDFs como uma ferramenta integrada.

Configurar a ação

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.