> This documentation belongs to Invofox, an AI-powered document processing
> platform. The API extracts structured data (fields) from unstructured
> documents (invoices, contracts, forms, bank statements, and more).
> Key concepts: Account, Environment, Document Type, Field, File, Import,
> and Document. When answering, prefer the exact terminology defined in the
> Glossary and cite the relevant API Reference endpoint when applicable.

# Integrar Invofox

> Guía completa para integrar la API de procesamiento de documentos de Invofox — consigue tu API key, sube un documento y recupera JSON estructurado y limpio mediante webhooks o polling.

**Invofox es una sola API para extraer datos estructurados de PDFs e imágenes** — envía cualquier documento (facturas, recibos, extractos bancarios, albaranes, contratos y muchos más, incluidos tipos de documento personalizados) y recibe JSON limpio y estructurado. Por dentro es una plataforma de procesamiento inteligente de documentos (IDP): OCR + IA que clasifican cada documento y extraen sus campos automáticamente — sin plantillas, sin introducción manual de datos.

Esta página es la integración esencial — el **camino directo** ("happy path"), de la subida al JSON. Para casos de uso, precisión y precios, consulta [invofox.com →](https://www.invofox.com/en/)

<Tip>
**¿Usas un agente de IA para programar?** Conéctate al servidor MCP de Invofox para que tu agente pueda buscar en esta documentación en tiempo real. [Integrar con un agente de IA →](/documentation/integrate-with-an-ai-agent)
</Tip>

## Paso 1 — Consigue tu API key

Las API keys están vinculadas a un entorno. Para crear una:

1. Inicia sesión en [app.invofox.com](https://app.invofox.com) y abre tu entorno — [crea una cuenta gratis](https://app.invofox.com/signup) si aún no tienes una.
2. Pulsa **API y Webhooks** en el menú de la izquierda.
3. Crea una nueva API key y cópiala.

## Paso 2 — Sube un documento

Envía tu archivo como `multipart/form-data` con un campo JSON `info`. La respuesta devuelve un `documentId` — es todo lo que necesitas. [Referencia completa de la API →](https://developers.invofox.com/api-reference/ingest-reference/files/upload-direct-controller-upload-direct)

<div className="ivf-endpoint"><span className="ivf-method ivf-method-post">POST</span><span>https://api.invofox.com/v1/ingest/uploads</span></div>

<CodeBlocks>

**`cURL`**

```bash title="cURL"
curl -s -X POST "https://api.invofox.com/v1/ingest/uploads" \
  -H "x-api-key: $INVOFOX_API_KEY" \
  -F "files=@invoice.pdf" \
  -F 'info={"type":"<TYPE_ID>","clientData":{"internalId":"inv-1234"}}'
```

**`Python`**

```python title="Python"
import os, json, requests

headers = {"x-api-key": os.environ["INVOFOX_API_KEY"]}

with open("invoice.pdf", "rb") as f:
    resp = requests.post(
        "https://api.invofox.com/v1/ingest/uploads",
        headers=headers,
        files=[("files", ("invoice.pdf", f, "application/pdf"))],
        data={"info": json.dumps({"type": "<TYPE_ID>", "clientData": {"internalId": "inv-1234"}})}
    ).json()

document_id = resp["files"][0]["documentId"]
print("Document ID:", document_id)
```

**`Node.js`**

```javascript title="Node.js"
import fs from 'fs';
import FormData from 'form-data';
import fetch from 'node-fetch';

const headers = { 'x-api-key': process.env.INVOFOX_API_KEY };

const form = new FormData();
form.append('files', fs.createReadStream('invoice.pdf'), 'invoice.pdf');
form.append('info', JSON.stringify({ type: '<TYPE_ID>', clientData: { internalId: 'inv-1234' } }));

const resp = await fetch('https://api.invofox.com/v1/ingest/uploads', {
  method: 'POST',
  headers: { ...headers, ...form.getHeaders() },
  body: form
}).then(r => r.json());

const documentId = resp.files[0].documentId;
console.log('Document ID:', documentId);
```
</CodeBlocks>

### El campo `info`

| Campo | Tipo | Obligatorio | Descripción |
| --- | --- | --- | --- |
| `type` | string | <span className="ivf-badge ivf-badge-blue">Obligatorio</span> | El Document Type a extraer — su `id` o `alias`. Lo encuentras en **Invofox → Document Types**. \* |
| `clientData` | object | <span className="ivf-badge ivf-badge-gray">Opcional</span> | Cualquier objeto JSON que quieras que Invofox guarde y devuelva junto al documento — tanto en la respuesta del GET como en el payload del webhook. Útil para llevar tus propios identificadores: `{"internalId": "inv-1234"}`. |

<Info title="Dónde encontrar los IDs de Document Type">
- Abre **Document Types** en el menú de la izquierda de Invofox.
- Cada Document Type muestra una tarjeta con su **`id`** y su **`alias`**.
- Usa el **`alias`** si lo tiene; si no, usa el **`id`**.
- **¿Necesitas un Document Type que no está?** Invofox puede definir Document Types personalizados para tu caso — escribe a [support@invofox.com](mailto:support@invofox.com).
</Info>

### Respuesta de la subida

La subida devuelve inmediatamente un `documentId` — no los datos extraídos. Invofox procesa el documento de forma asíncrona. Guarda el `documentId` de `files[0]` y úsalo en el Paso 3 para recuperar los resultados.

**`Respuesta de la subida`**

```json title="Respuesta de la subida"
{
  "accountId": "000000000000000000000006",
  "environmentId": "00000000000000000000001c",
  "importId": "00000000000000000000001e",
  "files": [
    {
      "id": "00000000000000000000001f",
      "filename": "invoice.pdf",
      "documentId": "000000000000000000000020"   // ← guarda esto
    }
  ]
}
```

## Paso 3 — Obtén los datos extraídos

El procesamiento es asíncrono. **Los webhooks son la opción recomendada**; el polling vale para pruebas rápidas y prototipos.

<Cards>
  <Card title="Opción A · Webhooks (Recomendado)" icon="bolt">
    Invofox envía un evento `document.processed` a tu servidor cuando la extracción termina. Orientado a eventos, sin sobrecarga de polling. Recomendado para todas las integraciones en producción.
  </Card>
  <Card title="Opción B · Polling" icon="arrows-rotate">
    Sin infraestructura — ideal para prototipos y pruebas rápidas. No recomendado para producción.
  </Card>
</Cards>

<Info>
Uses el método que uses, el **conjunto de campos lo define el Document Type configurado en tu entorno — no es fijo**. La **estructura** siempre es la misma: cada campo es un objeto `{ "value": ... }`, que puede anidarse, con arrays para las líneas. Para ver los campos exactos de tu Document Type, consulta **Document Types** en el panel o procesa un documento de ejemplo.
</Info>

### Opción A · Webhooks (recomendado para producción)

En Invofox, abre tu entorno y ve a **API y Webhooks → Webhooks** para añadir la URL de tu endpoint. Tu servidor recibirá entonces un evento `document.processed` en cuanto termine la extracción.

Para la **lista completa de eventos y sus esquemas de payload** (más firma y verificación), consulta la [Referencia de Webhooks →](https://developers.invofox.com/webhooks-reference/webhooks-reference/document-processing/receive-document-created). El ejemplo de abajo muestra un payload `document.processed`.

**`payload document.processed`**

```json title="payload document.processed"
{
  "type": "document.processed",
  "version": "1.2",
  "timestamp": 1781834535319,
  "url": "",
  "data": {                                // ← aquí vive el documento (no bajo "result" como en el GET); sin flags de permisos
    "_id": "000000000000000000000020",
    "clientData": { "internalId": "inv-1234" },   // ← el mismo clientData que enviaste en la subida
    "type": "00000000000000000000001d",           // ← el id del Document Type (o su alias, si lo tiene)
    "name": "invoice.pdf",
    "publicState": "approved",
    "confidence": "high",
    "pageCount": 1,
    "images": [
      "https://storage.invofox.com/documents/000000000000000000000020/page-1.jpeg?token=..."
    ],
    "original": "https://storage.invofox.com/documents/000000000000000000000020/original.pdf?token=...",
    "data": {                              // ← campos extraídos en data.data.<campo>
      "receiptNumber":  { "value": "A16030202" },
      "issueDate":      { "value": "2023-12-04" },
      "subtotalAmount": { "value": 31.32 },
      "taxAmount":      { "value": 0 },
      "totalAmount":    { "value": 31.32 },
      "paymentMethod":  { "value": "Transferencia bancaria" },
      "merchant":       { "name": { "value": "Invofox Inc" } },
      "items": [
        { "description": { "value": "Permanente Sharpie" }, "quantity": { "value": 1 }, "unitPrice": { "value": 2.1 }, "totalAmount": { "value": 2.1 } }
      ]
    }
  }
}
```

<Warning>
Un archivo también puede fallar **antes de producir ningún documento** (protegido con contraseña, corrupto, formato no soportado). Escucha el webhook `file.rejected` para no esperar eternamente un documento que nunca llegará — esto aplica tanto si usas webhooks como polling. Consulta [Archivos rechazados](/documentation/rejected-files).
</Warning>

### Opción B · Polling

Haz polling a `GET /documents/{documentId}` con backoff exponencial (empieza en 5 s, duplica en cada reintento). El endpoint puede devolver 404 durante los primeros segundos — es lo esperado, sigue haciendo polling. Para cuando recibas un 200 con `publicState` en `approved`, `pendingCorrection` o `discarded`.

<div className="ivf-endpoint"><span className="ivf-method ivf-method-get">GET</span><span>https://api.invofox.com/documents/{documentId}</span></div>

Los campos de la respuesta final viven bajo `result.data`. El ejemplo de abajo es ilustrativo.

**`GET /documents/{documentId}`**

```json title="GET /documents/{documentId}"
{
  "canEdit": true, "canComment": false, "canLock": true, "canAction": true,   // ← flags de permisos (no están en el webhook)
  "result": {
    "_id": "000000000000000000000020",
    "clientData": { "internalId": "inv-1234" },   // ← tu clientData, devuelto sin cambios
    "type": "00000000000000000000001d",           // ← el id del Document Type (o su alias, si lo tiene)
    "name": "invoice.pdf",
    "publicState": "approved",
    "confidence": "high",
    "pageCount": 1,
    "images": [
      "https://storage.invofox.com/documents/000000000000000000000020/page-1.jpeg?token=..."
    ],
    "original": "https://storage.invofox.com/documents/000000000000000000000020/original.pdf?token=...",
    "data": {                              // ← campos extraídos en result.data.<campo>
      "receiptNumber":  { "value": "A16030202" },
      "issueDate":      { "value": "2023-12-04" },
      "subtotalAmount": { "value": 31.32 },
      "taxAmount":      { "value": 0 },
      "totalAmount":    { "value": 31.32 },
      "paymentMethod":  { "value": "Transferencia bancaria" },
      "merchant":       { "name": { "value": "Invofox Inc" } },
      "items": [
        { "description": { "value": "Permanente Sharpie" }, "quantity": { "value": 1 }, "unitPrice": { "value": 2.1 }, "totalAmount": { "value": 2.1 } }
      ]
    }
  }
}
```

## Pasos opcionales adicionales

### Envía feedback sobre los valores extraídos

Si un valor extraído falta o es incorrecto, puedes devolver el valor correcto vía `PUT /documents/{id}`. Cada corrección alimenta directamente el entrenamiento del modelo, mejorando la precisión de extracción con el tiempo — automáticamente, sin configuración extra. Consulta la página [Bucle de feedback](/documentation/feedback-loop) para la referencia completa.

## Funciones adicionales

La integración esencial está completa. Estas funciones están disponibles si tu caso de uso las requiere:

<Cards>
  <Card title="Bucle de feedback" icon="pen" href="/documentation/feedback-loop">
    Devuelve las correcciones humanas a la API para cerrar el ciclo de revisión.
  </Card>
  <Card title="Splitter" icon="scissors" href="/documentation/splitter">
    Sube un PDF que contiene varios documentos y recíbelos por separado, automáticamente.
  </Card>
  <Card title="Classifier" icon="tag" href="/documentation/classifier">
    Olvídate de indicar el tipo de documento — Invofox lo detecta automáticamente.
  </Card>
</Cards>