API de flujo de trabajo validado

Valida el flujo de trabajo antes de usar la API

Empieza en la estación de trabajo, confirma que el resultado revisado coincide con tu flujo de trabajo y luego usa la API para ejecuciones de extracción repetibles.

Base: https://pdf2text.ai/api/v1

Autenticación

Todas las solicitudes a la API requieren un token Bearer en el encabezado Authorization. Genera claves desde la configuración de la cuenta después de validar un flujo de trabajo repetible.

Gestionar claves API
# Set your API key
export P2T_API_KEY="your_api_key_here"

# Include in all requests
curl -H "Authorization: Bearer $P2T_API_KEY" ...
import requests
import os

API_KEY = os.environ["P2T_API_KEY"]
headers = {"Authorization": f"Bearer {API_KEY}"}
const API_KEY = process.env.P2T_API_KEY;

const headers = {
  'Authorization': `Bearer ${API_KEY}`
};

Límites de uso

Firm incluye 1500 páginas al mes para flujos de trabajo revisados en la estación de trabajo y ejecuciones de extracción validadas con la API. Cada página procesada consume una página de esa asignación.

El uso se mide por páginas procesadas, no por llamadas a la API. Subir archivos y descargar resultados o exportaciones no consume páginas, pero volver a ejecutar la extracción procesa y consume esas páginas de nuevo.

Se admiten subidas en PDF, PNG, JPEG y WebP, de hasta 50 MiB por archivo. La implementación actual también limita la solicitud multipart completa a 100 MiB, incluidos todos los archivos y la sobrecarga del formulario. Las subidas están limitadas a 20 archivos por solicitud, 100 archivos por grupo, 500 páginas por documento o ejecución y 1,000 páginas almacenadas por grupo. Las imágenes pueden tener hasta 20,000 píxeles por lado y 40 megapíxeles; se rechazan las páginas PDF que superarían esos límites de rasterización con la resolución de renderizado del OCR.

No hay una cuota separada de llamadas a la API. Las ejecuciones de extracción son asíncronas y entran en la cola de procesamiento, por lo que el tiempo de finalización puede variar según el tamaño del documento y la carga del sistema.

Los límites de uso razonable son, de forma predeterminada, 30 subidas, 60 inicios de ejecución y 600 lecturas o exportaciones por cuenta por hora. Una respuesta 429 incluye Retry-After; espera ese intervalo antes de volver a intentarlo.

Usa la estación de trabajo para validar los formatos de los documentos, las reglas de revisión y los formatos de exportación antes de depender de la automatización por API.

Comparar planes
POST

Cargar Documentos

Sube uno o más archivos PDF, PNG, JPEG o WebP para crear un grupo de documentos. Los bytes de los archivos, el número de páginas y las dimensiones de las imágenes se verifican antes de guardar nada. Una subida correcta devuelve 201 Created con el page_count verificado de cada documento.

Endpoint

POST /api/v1/documents/upload/

Parámetros

file / files binary PDF, PNG, JPEG o WebP (obligatorio; repite el campo files para subir varios archivos)
grouping_id uuid Opcional. Agrégalo a uno de tus grupos de API existentes. Los espacios de trabajo anónimos no se pueden reclamar por UUID, y una ejecución activa hace que su grupo sea inmutable hasta que termine.
document_type string Opcional. Sugerencia de clasificación.
password string Opcional. Abre los PDF protegidos con contraseña en esta solicitud. Solo se usa para abrir los archivos y no se guarda. Sin ella, ese PDF devuelve encrypted_pdf; una incorrecta devuelve pdf_password_incorrect, y los intentos fallidos repetidos para un archivo devuelven 429.
# Upload a PDF file
curl -X POST https://pdf2text.ai/api/v1/documents/upload/ \
  -H "Authorization: Bearer $P2T_API_KEY" \
  -F "file=@invoice.pdf"

# Add to existing group
curl -X POST https://pdf2text.ai/api/v1/documents/upload/ \
  -H "Authorization: Bearer $P2T_API_KEY" \
  -F "file=@invoice2.pdf" \
  -F "grouping_id=a1b2c3d4-..."
import requests

url = "https://pdf2text.ai/api/v1/documents/upload/"

# Upload single file
with open("invoice.pdf", "rb") as f:
    response = requests.post(
        url,
        headers=headers,
        files={"file": f}
    )

data = response.json()
group_id = data["group_id"]
const { readFile } = require('node:fs/promises');

const form = new FormData();
form.append(
  'file',
  new Blob([await readFile('invoice.pdf')], { type: 'application/pdf' }),
  'invoice.pdf'
);

const response = await fetch(
  'https://pdf2text.ai/api/v1/documents/upload/',
  {
    method: 'POST',
    headers,
    body: form
  }
);
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);
const { group_id } = await response.json();
201 Created
{
  "status": "success",
  "group_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "documents": [
    {
      "doc_id": 42,
      "uid": "1847f600-...",
      "grouping_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "original_filename": "invoice.pdf",
      "file_type": "pdf",
      "page_count": 3,
      "status": "pending"
    }
  ]
}

Agrega archivos a un grupo solo antes de su primera ejecución. Para facturas posteriores, crea un grupo nuevo; de lo contrario, una ejecución sin filtros procesa todos los documentos que ya están en ese grupo.

POST

Iniciar Ejecución de Extracción

Inicia el procesamiento asíncrono de un grupo de documentos. Usa el enrutamiento automático cuando PDF2TEXT deba clasificar los documentos antes de la extracción.

Envía un encabezado Idempotency-Key en cada solicitud de inicio. Repetir la misma clave y el mismo cuerpo devuelve la misma ejecución; reutilizar la clave para una solicitud diferente devuelve 409. Después de un fallo terminal, usa una clave nueva para crear intencionalmente una ejecución de reemplazo. Una ejecución recién puesta en cola devuelve 202 Accepted. Solo puede haber una ejecución activa por grupo a la vez, y las ejecuciones activas reservan las páginas de la cuenta que pueden procesar.

Una respuesta 202 confirma que la ejecución fue aceptada, no que todas las páginas solicitadas estén cubiertas. Si el saldo compartido de la cuenta es menor que la ejecución, la API procesa las páginas reservadas y termina como parcial con credit_limit_reached=true. Comprueba el estado terminal de la ejecución antes de dar la importación por completada.

Las URL de callback deben usar HTTPS público y no pueden redirigir a otro destino. La entrega es asíncrona, tiene un tiempo de espera de 10 segundos por solicitud y realiza hasta cuatro reintentos ante errores de conexión transitorios, respuestas HTTP 429 y HTTP 5xx, con intervalos de espera de 30 segundos, 2 minutos y 10 minutos.

Cuando se proporciona callback_secret, verifica X-PDF2TEXT-Signature calculando HMAC-SHA256 sobre el cuerpo exacto de la solicitud y comparándolo con el valor sha256=. Usa X-PDF2TEXT-Run-ID o X-PDF2TEXT-Idempotency-Key para eliminar entregas duplicadas.

The callback JSON body is {"event": "idp.run.completed", "run": {...}}; run uses the same full result shape as GET ?include=results. A signature header is sent only when callback_secret was included in the start request.

Endpoint

POST /api/v1/groups/{group_id}/runs/

Cuerpo de la Solicitud

auto_route boolean Clasificación automática (predeterminado: true)
extraction_mode enum auto, raw_text, financial_table, general_table o unified. Usa template_id o template_slug para un esquema personalizado.
template_id / template_slug uuid / string Usa exactamente uno para forzar una plantilla específica
selected_pages array Lista opcional no vacía de {docUid, pageNumber}; las páginas no válidas rechazan toda la solicitud
construction_project_id uuid Proyecto opcional perteneciente a la cuenta de API
callback_url string URL de Webhook
callback_secret string Secreto de firma HMAC
# Start extraction with auto-routing
curl -X POST https://pdf2text.ai/api/v1/groups/$GROUP_ID/runs/ \
  -H "Authorization: Bearer $P2T_API_KEY" \
  -H "Idempotency-Key: invoice-import-123" \
  -H "Content-Type: application/json" \
  -d '{"auto_route": true}'
# Start extraction run
url = f"https://pdf2text.ai/api/v1/groups/{group_id}/runs/"

response = requests.post(
    url,
    headers={**headers, "Idempotency-Key": "invoice-import-123"},
    json={"auto_route": True}
)

run_data = response.json()
run_id = run_data["run_id"]
// Start extraction run
const response = await fetch(
  `https://pdf2text.ai/api/v1/groups/${groupId}/runs/`,
  {
    method: 'POST',
    headers: {
      ...headers,
      'Idempotency-Key': 'invoice-import-123',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ auto_route: true })
  }
);

const { run_id } = await response.json();
202 Accepted
{
  "status": "success",
  "run_id": "b3143b91-...",
  "job_id": "idp-run-b3143b91-...",
  "group_name": "ocr_job_a1b2c3d4...",
  "idempotent_replay": false,
  "run": {
    "id": "b3143b91-...",
    "status": "queued",
    "job_id": "idp-run-b3143b91-...",
    "total_pages": 3,
    "pages_processed": 0
  }
}
GET

Obtener Resultados

Consulta el endpoint de ejecución o usa webhooks para obtener los resultados de extracción. Exporta como JSON o Excel.

La respuesta predeterminada de la ejecución es ligera para consultas frecuentes y nunca se almacena en caché. Lee run.status dentro del objeto run anidado. Los estados terminales son complete, partial y error. Después de un estado terminal, solicita include=results una vez para obtener full_text, structured_output y documents.

credits_remaining se conserva por compatibilidad y registra el saldo histórico después de esa ejecución. credits_remaining_after_run nombra explícitamente el mismo valor histórico, mientras que account_credits_remaining indica el saldo compartido actual de la cuenta en el momento en que se genera la respuesta.

Endpoints

GET /api/v1/runs/{run_id}/ GET /api/v1/runs/{run_id}/?include=results GET /api/v1/runs/{run_id}/export.json GET /api/v1/runs/{run_id}/export.xlsx GET /api/v1/runs/{run_id}/export.xlsx?date_format=MM/DD/YYYY

Para extractos bancarios, export.xlsx también incluye hojas CSV de QuickBooks y CSV de Xero. Sus fechas usan el formato guardado en tu cuenta o, si no, el orden del país del extracto. Pasa date_format (DD/MM/YYYY, MM/DD/YYYY, YYYY/MM/DD o YYYY-MM-DD) para elegirlo; las demás hojas mantienen YYYY-MM-DD.

Códigos de Estado de Respuesta

200 401 404
# Lightweight status poll
curl https://pdf2text.ai/api/v1/runs/$RUN_ID/ \
  -H "Authorization: Bearer $P2T_API_KEY"

# Fetch completed results once, then export
curl "https://pdf2text.ai/api/v1/runs/$RUN_ID/?include=results" \
  -H "Authorization: Bearer $P2T_API_KEY"

curl -o results.xlsx \
  https://pdf2text.ai/api/v1/runs/$RUN_ID/export.xlsx \
  -H "Authorization: Bearer $P2T_API_KEY"
import time

run_url = f"https://pdf2text.ai/api/v1/runs/{run_id}/"
terminal = {"complete", "partial", "error"}
delay = 2

# Poll lightweight state with bounded exponential backoff
while True:
    response = requests.get(run_url, headers=headers)
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", delay))
        time.sleep(retry_after)
        delay = min(30, max(10, delay * 2))
        continue
    response.raise_for_status()
    run = response.json()["run"]

    if run["status"] in terminal:
        break

    time.sleep(delay)
    delay = min(30, max(10, delay * 2))

if run["status"] == "error":
    raise RuntimeError(run["error_message"])

results = requests.get(run_url, params={"include": "results"}, headers=headers).json()["run"]

excel = requests.get(
    f"{run_url}export.xlsx",
    headers=headers
)
with open("results.xlsx", "wb") as f:
    f.write(excel.content)
// Poll lightweight state
const pollResults = async (runId) => {
  const runUrl = `https://pdf2text.ai/api/v1/runs/${runId}/`;
  const terminal = new Set(['complete', 'partial', 'error']);
  let delay = 2000;
  while (true) {
    const response = await fetch(runUrl, { headers });
    if (response.status === 429) {
      const retryAfter = Number(response.headers.get('Retry-After') || delay / 1000);
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      delay = Math.min(30000, Math.max(10000, delay * 2));
      continue;
    }
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    const { run } = await response.json();

    if (terminal.has(run.status)) {
      if (run.status === 'error') throw new Error(run.error_message);
      const resultResponse = await fetch(`${runUrl}?include=results`, { headers });
      return (await resultResponse.json()).run;
    }

    await new Promise(r => setTimeout(r, delay));
    delay = Math.min(30000, Math.max(10000, delay * 2));
  }
};

const results = await pollResults(runId);
Respuesta con include=results
{
  "status": "success",
  "run": {
    "id": "b3143b91-...",
    "status": "complete",
    "total_pages": 3,
    "pages_processed": 3,
    "credits_remaining_after_run": 497,
    "account_credits_remaining": 497,
    "full_text": "...",
    "structured_output": { /* grouped output */ },
    "documents": [
      {
        "doc_id": 42,
        "document_name": "invoice.pdf",
        "ocr_text": "...",
        "structured_output": { /* document output */ }
      }
    ]
  }
}
GET

Plantillas

Lista las plantillas de extracción disponibles. Usa los IDs de plantilla para forzar esquemas de extracción específicos.

Endpoint

GET /api/v1/templates/
Administrar Plantillas
# List available templates
curl https://pdf2text.ai/api/v1/templates/ \
  -H "Authorization: Bearer $P2T_API_KEY"
# List available templates
response = requests.get(
    "https://pdf2text.ai/api/v1/templates/",
    headers=headers
)

templates = response.json()["templates"]
for t in templates:
    print(f"{t['name']}: {t['id']}")
// List available templates
const response = await fetch(
  'https://pdf2text.ai/api/v1/templates/',
  { headers }
);

const { templates } = await response.json();
templates.forEach(t => console.log(`${t.name}: ${t.id}`));
Respuesta
{
  "status": "success",
  "templates": [
    {
      "id": "198aa5be-ea8b-4d67-bdb5-625f5d7d29e8",
      "slug": "invoice",
      "name": "Invoice",
      "description": "Standard invoice extraction",
      "extraction_mode": "financial_table"
    },
    {
      "id": "4317707a-f0da-4c2f-a1ec-d0119d96b55c",
      "slug": "receipt",
      "name": "Receipt",
      "description": "Receipt and expense extraction",
      "extraction_mode": "financial_table"
    }
  ]
}

¿Necesitas Ayuda?

Usa la cola de revisión para inspeccionar los campos extraídos y conservar el contexto de la revisión.