API REST
Endpoints HTTPS com uma chave de API bearer. DTOs estáveis, erros previsíveis, criação idempotente.
Ver o ciclo de vidaUm ciclo de vida do trabalho previsível sobre uma API REST e um MCP hospedado equivalente: crie um trabalho, espere por ready, obtenha o Markdown, libere o espaço. A API e o MCP nunca ignoram os limites do produto.
Escolha a integração que se encaixa. Ambas chamam o mesmo motor de conversão e obedecem aos mesmos espaços, limites e retenção.
Endpoints HTTPS com uma chave de API bearer. DTOs estáveis, erros previsíveis, criação idempotente.
Ver o ciclo de vidaUm endpoint gerenciado de Model Context Protocol que expõe a conversão como ferramentas de agente: uma camada fina sobre a mesma API.
Conectar MCPImporte um spec OpenAPI reduzido em um Custom GPT do ChatGPT para que ele possa converter PDF como ferramenta integrada.
Configurar a actionA API e o MCP usam chaves de API bearer, distintas da via assinada por dispositivo que a extensão do Chrome usa. É necessária uma conta gratuita do Google para gerar chaves.
Authorization: Bearer p2m_… em cada requisição.Idempotency-Key opcional na criação permite repetir com segurança sem trabalhos duplicados.Scopes. Cada chave de API carrega scopes: jobs:create, jobs:read, jobs:download, jobs:delete (os padrões), mais settings:read / settings:write. Crie chaves de privilégio mínimo; tanto a API REST quanto as ferramentas MCP aplicam os scopes da chave.
Um ciclo de vida previsível, duas formas de conduzi-lo: chame a API REST a partir do seu próprio código, ou use as ferramentas equivalentes do MCP hospedado. Nunca reivindique um resultado antes de status=ready.
Faça POST de uma URL de PDF ou envie bytes. Você recebe de volta um id de trabalho e um espaço. Idempotency-Key é respeitado, mas opcional.
Consulte o trabalho até ready ou error, ou registre um webhook assinado nos planos pagos em vez de consultar.
Baixe o resultado assim que estiver pronto. Leia truncated e pages para saber se um documento longo foi retornado em parte.
Libere um espaço quando terminar. Excluir trabalhos na fila ou em processamento é destrutivo: confirme isso em clientes voltados ao usuário.
# 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 formas estáveis e códigos HTTP previsíveis (400 entrada inválida, 401 auth, 404 trabalho desconhecido, 409 sem espaço livre / slots_full, 413 grande demais, 429 limite de taxa). O esquema completo está no spec OpenAPI.
Create aceita um url JSON ou um file multipart, mais file_name, external_id, tags opcionais e callback_url / callback_secret para um webhook por trabalho. A criação em lote é tudo-ou-nada e deve caber nos seus espaços livres.
Conta e uso. Consulte seu plano, 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.
As mesmas quatro chamadas a partir de qualquer linguagem. Aqui com requests. Para um passo a passo completo com tratamento de erros, veja o tutorial de 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)
# 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"
// 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 webhooks está na seção Webhooks; a configuração do cliente MCP está na seção MCP. Esquema completo: OpenAPI.
Conecte um agente compatível ao nosso endpoint MCP gerenciado. As ferramentas são uma camada fina sobre a API REST, então cada chamada obedece aos mesmos espaços, limites e retenção.
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.
O mesmo ciclo de vida mais os limites, expostos como sete ferramentas. Cada uma respeita os scopes da chave; as respostas de tools/call incluem slot_usage e tier.
Espere por ready antes de usar a saída; confirme antes de excluir trabalhos na fila/em processamento; trate truncated e 429 Retry-After. (Os nomes de ferramenta levam o prefixo pdf_to_markdown_.)
// MCP client config (hosted, no local process)
{
"mcpServers": {
"pdf2md": {
"url": "https://pdf2md.dev/api/v2/mcp",
"headers": {
"Authorization": "Bearer p2m_…"
}
}
}
}
Publicamos dois specs: o OpenAPI completo para desenvolvedores, e um spec de action reduzido com o subconjunto seguro e mínimo para clientes de IA e Custom GPT Actions do ChatGPT.
O contrato completo: cada endpoint, parâmetro, DTO e erro. Gere clientes ou explore-o nas suas ferramentas.
Um subconjunto mínimo de action (criar, status, obter) para Custom GPT Actions do ChatGPT. Importe a URL, defina sua chave de API como auth, e seu GPT converte PDF de forma nativa.
O spec reduzido é uma conveniência para clientes de IA, não uma fronteira de segurança: aplicam-se a mesma auth, scopes e limites que na API completa.
Os limites vêm do seu plano e se aplicam de forma idêntica em cada superfície. Os valores ao vivo estão na página de preços.
Os planos pagos ampliam espaços, tamanho de arquivo, orçamento de tempo, retenção e limites de taxa, e adicionam webhooks e criação em lote. Comparar planos →
429 com um cabeçalho Retry-After: recue e tente de novo.409. Libere um espaço com delete, ou espere um trabalho terminar.Nos planos pagos, registre um webhook assinado (ou passe um callback_url por trabalho) e fazemos 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 leva conteúdo do documento, então obtenha o Markdown pela API depois de recebê-lo.
Faça POST de uma URL HTTPS (com proteção SSRF) e um filtro events opcional. O segredo de assinatura whsec_… é retornado uma única vez. Ou defina callback_url + callback_secret em um único trabalho.
Fazemos POST de JSON com os cabeçalhos X-P2M-Event, X-P2M-Timestamp, X-P2M-Delivery e X-P2M-Signature.
Recalcule a assinatura, confirme com 2xx, e seja idempotente (as entregas podem repetir 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)
Coloque estas regras no system prompt de um agente para que ele conduza as ferramentas corretamente e nunca invente resultados.
Nunca reivindique nem resuma um resultado antes de status=ready. Enquanto estiver queued ou processing, continue consultando ou espere o webhook.
Excluir um trabalho queued ou processing é destrutivo. Pergunte ao usuário antes de chamar pdf_to_markdown_delete_job em um trabalho não finalizado.
Se truncated=true, diga ao usuário que o documento foi retornado em parte até o orçamento de tempo do plano, e ofereça um plano superior ou dividir o arquivo.
Diante de um 429, espere os segundos de Retry-After antes de tentar de novo. Não martele a fila.
Exclua os trabalhos finalizados que você não precisa mais para não esgotar seus espaços.
Comece por /llms.txt e o spec OpenAPI em vez de adivinhar endpoints a partir da prosa.
Tudo o que um agente precisa para integrar sem ler o código-fonte: um arquivo compacto de capacidades, um arquivo de contexto detalhado e o spec OpenAPI.