Ejecutar extracciones
Descripción general
El endpoint de extracción acepta un documento (codificado en base64), lo procesa a través de una plantilla que hayas definido y devuelve datos estructurados que coinciden con las variables de la plantilla. Una sola llamada a la API maneja todo el flujo -- carga, procesamiento con IA y salida estructurada.
Todas las solicitudes de extracción pasan por POST /v1/extractions/run.
Preparar tu documento
Antes de enviar un documento a la API, necesitas codificar el contenido del archivo en base64.
Restricciones:
- Tamaño máximo del cuerpo de la solicitud: 15 MB
- Tipos MIME compatibles:
application/pdf(PDF)application/vnd.openxmlformats-officedocument.wordprocessingml.document(DOCX)
# Base64-encode a PDF file
base64 -i invoice.pdf -o invoice_b64.txt
# Or inline (macOS / Linux)
PDF_BASE64=$(base64 -w 0 invoice.pdf)import { readFileSync } from "fs";
const pdfBuffer = readFileSync("invoice.pdf");
const pdfBase64 = pdfBuffer.toString("base64");import base64
with open("invoice.pdf", "rb") as f:
pdf_base64 = base64.b64encode(f.read()).decode("utf-8")WARNING
La codificación en base64 aumenta el tamaño del archivo aproximadamente un 33%. Un PDF de 10 MB se convierte en aproximadamente 13,3 MB después de la codificación, así que mantén tus archivos fuente por debajo de ~11 MB para respetar el límite de 15 MB de la solicitud.
Realizar la solicitud
Envía una solicitud POST a /v1/extractions/run con el siguiente cuerpo JSON:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
templateId | string | Sí | El ID de la plantilla con la que extraer |
fileName | string | Sí | Nombre original del archivo (por ejemplo, "invoice.pdf") |
pdfBase64 | string | Sí | Contenido del archivo codificado en base64 |
mimeType | string | Sí | Tipo MIME del archivo |
runId | string | No | Identificador opcional para agrupar múltiples extracciones en un lote |
curl -X POST https://api.docmap.io/v1/extractions/run \
-H "Authorization: Bearer dm_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl_abc123",
"fileName": "invoice.pdf",
"pdfBase64": "JVBERi0xLjQKJeLj...",
"mimeType": "application/pdf"
}'const response = await fetch("https://api.docmap.io/v1/extractions/run", {
method: "POST",
headers: {
Authorization: "Bearer dm_live_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_abc123",
fileName: "invoice.pdf",
pdfBase64: pdfBase64,
mimeType: "application/pdf",
}),
});
const { data } = await response.json();
console.log(data.extractedData);import requests
response = requests.post(
"https://api.docmap.io/v1/extractions/run",
headers={
"Authorization": "Bearer dm_live_your_api_key",
"Content-Type": "application/json",
},
json={
"templateId": "tmpl_abc123",
"fileName": "invoice.pdf",
"pdfBase64": pdf_base64,
"mimeType": "application/pdf",
},
)
data = response.json()["data"]
print(data["extractedData"])Entender la respuesta
Una extracción exitosa devuelve una respuesta envuelta en un objeto data:
{
"data": {
"id": "ext_abc123def456",
"userId": "user_789",
"templateId": "tmpl_abc123",
"templateName": "Invoice Parser",
"fileName": "invoice.pdf",
"status": "completed",
"extractedData": {
"vendor_name": "Acme Corp",
"invoice_number": "INV-2024-001",
"total_amount": 1250.00,
"line_items": [
{ "description": "Widget A", "quantity": 10, "unit_price": 125.00 }
]
},
"error": null,
"variables": [
{ "name": "vendor_name", "type": "string", "description": "Company name of the vendor" },
{ "name": "invoice_number", "type": "string", "description": "Invoice reference number" },
{ "name": "total_amount", "type": "number", "description": "Total invoice amount" },
{ "name": "line_items", "type": "array", "description": "List of line items" }
],
"source": "api",
"runId": null,
"processingTimeMs": 3420,
"createdAt": "2025-07-15T10:30:00.000Z"
}
}| Campo | Descripción |
|---|---|
id | ID único de extracción (con prefijo ext_) |
status | "processing" mientras se ejecuta (modo asíncrono), "completed" si los datos se extrajeron correctamente, "failed" si el procesamiento encontró un error |
extractedData | Un objeto cuyas claves coinciden con los nombres de las variables de tu plantilla. null si la extracción falló |
error | Cadena con el mensaje de error si la extracción falló. null en caso de éxito |
processingTimeMs | Tiempo que la IA tardó en procesar el documento, en milisegundos |
source | "api" cuando se activó mediante clave API, "dashboard" cuando se activó desde la interfaz web |
variables | Las definiciones de variables de la plantilla que se usaron para esta extracción |
runId | El identificador de lote que proporcionaste, o null si no se especificó |
templateName | Nombre legible de la plantilla utilizada |
createdAt | Marca de tiempo ISO 8601 de cuándo se creó la extracción |
TIP
Siempre verifica el campo status antes de acceder a extractedData. Si status es "failed", el campo error contiene una descripción de lo que salió mal.
Extracciones por lotes
Para procesar múltiples archivos como un lote lógico, pasa el mismo runId a cada solicitud de extracción. Esto no cambia cómo se procesan los documentos -- cada archivo se extrae de forma independiente -- pero te permite consultar todos los resultados de un lote juntos.
const runId = "batch-invoices-2025-07";
const files = ["invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"];
// Process each file with the same runId
const results = await Promise.all(
files.map(async (fileName) => {
const pdfBase64 = readFileSync(fileName).toString("base64");
const response = await fetch("https://api.docmap.io/v1/extractions/run", {
method: "POST",
headers: {
Authorization: "Bearer dm_live_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_abc123",
fileName,
pdfBase64,
mimeType: "application/pdf",
runId,
}),
});
return response.json();
})
);Luego recupera todas las extracciones del lote:
curl "https://api.docmap.io/v1/extractions?runId=batch-invoices-2025-07" \
-H "Authorization: Bearer dm_live_your_api_key"const response = await fetch(
"https://api.docmap.io/v1/extractions?runId=batch-invoices-2025-07",
{
headers: { Authorization: "Bearer dm_live_your_api_key" },
}
);
const { data } = await response.json();
console.log(`Batch contains ${data.length} extractions`);response = requests.get(
"https://api.docmap.io/v1/extractions",
params={"runId": "batch-invoices-2025-07"},
headers={"Authorization": "Bearer dm_live_your_api_key"},
)
data = response.json()["data"]
print(f"Batch contains {len(data)} extractions")TIP
El endpoint de listado también admite filtrado por templateId y un parámetro limit (1--100, predeterminado 50). Puedes combinar filtros: ?runId=batch-001&templateId=tmpl_abc123&limit=100.
Flujo de trabajo asíncrono
Por defecto, las solicitudes de extracción son sincrónicas -- la API bloquea hasta que el procesamiento finaliza. Para extracciones de larga duración o cuando quieras evitar timeouts HTTP, usa el modo asíncrono añadiendo ?async=true a la URL. La API responde inmediatamente con un estado "processing", y consultas un endpoint separado hasta que el resultado esté listo.
Patrón de envío + consulta periódica
import { readFileSync } from "fs";
const API_BASE = "https://api.docmap.io";
const API_KEY = process.env.DOCMAP_API_KEY!;
// 1. Submit the extraction asynchronously
const submitResponse = await fetch(`${API_BASE}/v1/extractions/run?async=true`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_abc123",
fileName: "invoice.pdf",
pdfBase64: readFileSync("invoice.pdf").toString("base64"),
mimeType: "application/pdf",
}),
});
const { data: submitted } = await submitResponse.json();
console.log(`Extraction ${submitted.id} submitted, status: ${submitted.status}`);
// 2. Poll until complete
async function poll(extractionId: string): Promise<any> {
for (let i = 0; i < 30; i++) {
const res = await fetch(`${API_BASE}/v1/extractions/${extractionId}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const { data } = await res.json();
if (data.status !== "processing") return data;
await new Promise((r) => setTimeout(r, 2000));
}
throw new Error("Extraction timed out");
}
const result = await poll(submitted.id);
console.log(`Final status: ${result.status}`);
console.log("Extracted data:", result.extractedData);import base64
import time
import requests
API_BASE = "https://api.docmap.io"
API_KEY = "dm_live_your_api_key"
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
# 1. Submit the extraction asynchronously
with open("invoice.pdf", "rb") as f:
pdf_base64 = base64.b64encode(f.read()).decode("utf-8")
submit_response = requests.post(
f"{API_BASE}/v1/extractions/run?async=true",
headers=headers,
json={
"templateId": "tmpl_abc123",
"fileName": "invoice.pdf",
"pdfBase64": pdf_base64,
"mimeType": "application/pdf",
},
)
submitted = submit_response.json()["data"]
print(f"Extraction {submitted['id']} submitted, status: {submitted['status']}")
# 2. Poll until complete
def poll(extraction_id: str):
for _ in range(30):
res = requests.get(
f"{API_BASE}/v1/extractions/{extraction_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
data = res.json()["data"]
if data["status"] != "processing":
return data
time.sleep(2)
raise TimeoutError("Extraction timed out")
result = poll(submitted["id"])
print(f"Final status: {result['status']}")
print("Extracted data:", result["extractedData"])Cuándo usar el modo asíncrono
Usa el modo asíncrono cuando proceses documentos grandes, cuando tu cliente HTTP tenga timeouts cortos, o cuando quieras enviar múltiples extracciones y recoger los resultados después. Para la mayoría de las extracciones de un solo documento, el modo sincrónico es más sencillo.
Ejemplo completo de flujo de trabajo
Aquí hay un ejemplo completo de extremo a extremo en TypeScript que lee un PDF del disco, ejecuta una extracción y maneja tanto el éxito como el fallo:
import { readFileSync } from "fs";
const API_BASE = "https://api.docmap.io";
const API_KEY = process.env.DOCMAP_API_KEY!;
async function extractInvoice(filePath: string) {
// 1. Read and encode the PDF
const pdfBuffer = readFileSync(filePath);
const pdfBase64 = pdfBuffer.toString("base64");
const fileName = filePath.split("/").pop()!;
console.log(`Processing ${fileName} (${(pdfBuffer.length / 1024).toFixed(0)} KB)...`);
// 2. Run the extraction
const response = await fetch(`${API_BASE}/v1/extractions/run`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_invoice_parser",
fileName,
pdfBase64,
mimeType: "application/pdf",
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API error ${response.status}: ${error.error.message}`);
}
const { data } = await response.json();
// 3. Check the extraction result
if (data.status === "failed") {
console.error(`Extraction failed: ${data.error}`);
return null;
}
console.log(`Extraction completed in ${data.processingTimeMs}ms`);
console.log("Extracted data:", JSON.stringify(data.extractedData, null, 2));
return data.extractedData;
}
// Run it
extractInvoice("./invoices/invoice-001.pdf")
.then((result) => {
if (result) {
console.log(`Vendor: ${result.vendor_name}`);
console.log(`Total: $${result.total_amount}`);
}
})
.catch(console.error);