Integración por API

Cómo funciona la API

La API REST de Tavnit permite que tu propio código haga lo mismo que haces en la app: enviar documentos a un Flow, una Colección, un Splitter o un Pipeline; ejecutar Cleaners, Matchers, Inspectores, Fillers, Signals y Agentes; leer y escribir Buckets; gestionar los casos de un Subject, y aprobar o rechazar revisiones humanas.

  • URL base: https://run.tavnit.io/api. Todas las rutas de abajo son relativas a ella.
  • Cada solicitud lleva tu API key en el encabezado X-API-Key.
  • El procesamiento es asíncrono. Los endpoints que inician trabajo responden de inmediato 202 Accepted con un id, y el trabajo corre en segundo plano. Obtienes el resultado consultando (runs, runs de Agentes, Catches, casos) o en un webhook configurado en la función.
Funciones en Beta

Pipelines, Subjects, Matchers, Inspectores, Fillers, Signals y Nets están en Beta. Sus endpoints ya funcionan, pero algunos detalles todavía pueden cambiar.

Autenticación e IDs

API key

Abre Integraciones en la barra lateral de la app. La tarjeta Clave API muestra tu key (ahí puedes revelarla y copiarla). Cada miembro tiene su propia key en cada organización, y una solicitud actúa como ese miembro en esa organización.

Mantén tu API key en secreto. Regenerar, en la misma tarjeta, invalida la key actual de inmediato, y todo lo que la siga usando deja de funcionar.

Una solicitud sin una key válida recibe:

401
{
  "success": false,
  "error": "Authentication required",
  "message": "Please provide a valid X-API-Key header"
}

Roles

La key lleva tu rol. Los miembros con el rol Solo HITL solo pueden usar los endpoints de aprobar y rechazar revisiones humanas y los de la API key. Todos los endpoints de procesamiento y de datos los rechazan con 403 y Your role only permits HITL reviews. Consulta roles de usuario.

IDs

Cada Flow, Colección, Splitter, Cleaner, Bucket, Agente, Matcher, Inspector, Filler y Pipeline muestra su ID en su página de detalle, con un botón para copiarlo. Los recursos deben pertenecer a la organización de tu key: el ID de otra organización responde 403 o 404.

Envío de archivos

Los endpoints que reciben un documento lo aceptan de dos formas:

Subida multipart

Envía el archivo como multipart/form-data en un campo llamado file, con los demás campos como campos del formulario. Funciona en todos los endpoints de archivos.

Base64 en un cuerpo JSON

Envía un JSON con file_base64 (el contenido del archivo) y filename (con su extensión), más los demás campos. Es útil cuando una herramienta de automatización te da base64 en lugar de un archivo.

EndpointBase64Archivos aceptados
POST /runs/processSíPDF, imágenes (PNG, JPG, JPEG, JFIF, TIF, TIFF, WEBP, BMP, GIF), hojas de cálculo (XLSX, XLS, CSV)
POST /collections/processSíIgual que runs
POST /splits/runSíIgual que runs
POST /pipelines/{id}/executeSíPDF e imágenes
POST /signals/{id}/runSíAudio: MP3, MP4, MPEG, MPGA, M4A, WAV, WEBM
POST /sweeps/runNoHojas de cálculo: CSV, XLSX, XLS
Inspectores, Fillers, Subjects y casosNoEl documento como archivo multipart

Una solicitud puede pesar hasta 150 MB. El tipo de archivo se toma de la extensión del nombre.

Respuestas y errores

Las respuestas son JSON con un indicador success. Los errores traen un texto en error, a veces un message y claves adicionales que explican el problema:

Ejemplo 409
{
  "success": false,
  "error": "Bucket mismatch",
  "message": "bucket_name does not match the target bucket. Verify both bucket_id and bucket_name before retrying."
}
CódigoSignificado
200 / 201Hecho (lecturas, cancelaciones, aprobaciones) / creado (casos, fills, inspecciones).
202Aceptado: el trabajo quedó en cola. Guarda el id que devuelve.
400Falta un campo obligatorio o no es válido, el tipo de archivo no es compatible, o el recurso está inactivo o sin configurar.
401Falta la X-API-Key o no es válida.
402Tu organización no puede iniciar trabajo nuevo en este momento; contacta al equipo de Tavnit.
403El recurso es de otra organización, tu rol es Solo HITL o no eres revisor de ese elemento.
404El ID no existe en tu organización.
409Conflicto con el estado actual: nombre de Bucket que no coincide, ya cancelado o terminado, caso cerrado, espacio ya ocupado.
429Demasiados runs esperando turno en un Agente.
500Error inesperado. Puedes reintentar más tarde.

Referencia de endpoints

FunciónMétodo y rutaQué hace
FlowsPOST /runs/processExtrae un documento con un Flow
FlowsGET /runs/{run_id}Estado del run y datos extraídos
FlowsGET /runs/{run_id}/source-fileEl documento original
ColeccionesPOST /collections/processLa IA dirige el documento al Flow o Splitter correcto
ColeccionesGET /collection-runs/{id}/source-fileEl documento original
SplittersPOST /splits/runDivide un archivo con varios documentos
SplittersGET /splits/{split_id}/source-fileEl archivo original completo
CleanersPOST /sweeps/runSweep de una hoja de cálculo
CleanersPOST /cleaners/{cleaner_id}/processSweep de filas enviadas como JSON
BucketsPOST /buckets/writeAgrega o reemplaza filas
BucketsGET /buckets/readLee filas, paginadas
AgentesPOST /bots/{agent_id}/runsInicia un run del Agente
AgentesGET /bot-runs/{bot_run_id}Consulta un run del Agente
AgentesGET /bots/{agent_id}/runsLista los runs de un Agente
AgentesPOST /bot-runs/{bot_run_id}/cancelCancela un run del Agente
MatchersPOST /matchers/{matcher_id}/runCompara runs completados
InspectoresPOST /inspectors/{inspector_id}/processAgrega un documento a una inspección
FillersPOST /fillers/{filler_id}/fillsAbre un fill y agrega documentos
PipelinesPOST /pipelines/{pipeline_id}/executeEjecuta un Pipeline
SignalsPOST /signals/{signal_id}/runEstructura un archivo de audio (una Wave)
SubjectsPOST /subjects/{subject_id}/processDirige un documento a un caso
NetsPOST /nets/{net_id}/catchInicia un Catch
Revisión HumanaPOST /runs/{run_id}/hitl/approveAprueba o rechaza elementos en pausa
API keyGET /me/api-keyLee o regenera tu key

Abajo se detalla cada función, con sus demás endpoints.

Flows: procesa un documento

Envía un documento a un Flow. Tavnit crea un run y lo extrae en segundo plano.

POST/runs/process
* Envía file o bien file_base64 + filename.
CampoObligatorioDescripción
flow_idSíEl Flow que extrae el documento.
fileSí*El documento (multipart).
file_base64 + filenameSí*En lugar de file: el contenido en base64 y el nombre del archivo con su extensión.
content_typeNoTipo MIME de un archivo en base64.
sourceNoEtiqueta que se guarda en el run: api (predeterminada), email, manual_upload o collection.
Python
import requests

API_KEY = "YOUR_API_KEY"
FLOW_ID = "YOUR_FLOW_ID"

# ─────────────────────────────────────────────────────────────
# Option 1: Multipart file upload (binary)
# ─────────────────────────────────────────────────────────────
with open("document.pdf", "rb") as file:
    response = requests.post(
        "https://run.tavnit.io/api/runs/process",
        headers={"X-API-Key": API_KEY},
        data={
            "flow_id": FLOW_ID,
            "source": "api"
        },
        files={"file": file}
    )

print(response.json())


# ─────────────────────────────────────────────────────────────
# Option 2: Base64-encoded file (JSON body)
# ─────────────────────────────────────────────────────────────
import base64

with open("document.pdf", "rb") as file:
    file_base64 = base64.b64encode(file.read()).decode("utf-8")

response = requests.post(
    "https://run.tavnit.io/api/runs/process",
    headers={
        "X-API-Key": API_KEY,
        "Content-Type": "application/json"
    },
    json={
        "flow_id": FLOW_ID,
        "source": "api",
        "filename": "document.pdf",
        "file_base64": file_base64
    }
)

print(response.json())
Respuesta 202
{
  "success": true,
  "run_id": "8f1c2b7e-4d3a-4a91-9c11-2f7b6e0d5a44",
  "status": "queued",
  "auto_created_run": true,
  "message": "Run accepted for background processing. Poll the run for status or await the webhook."
}

Errores: 400 (sin archivo, sin flow_id, archivo no compatible o inválido), 403 (Flow de otra organización), 404 (Flow no encontrado). Una solicitud rechazada igual crea un run fallido cuando puede, y devuelve su run_id para que lo encuentres en Runs.

Consulta el run y sus datos

GET/runs/{run_id}

Consulta hasta que status sea final. Estados: queued, running, awaiting_approval (en pausa para revisión humana), completed, failed y cancelled. data trae las filas extraídas y sigue en null hasta que el run se completa, incluso mientras espera aprobación. Si columns viene con valor, úsalo para el orden de las columnas. attempt y previous_attempts muestran los reintentos automáticos. Agrega ?include_document=true para recibir también un enlace firmado al archivo original. Funciona con todos los runs, incluidos los creados por Colecciones, Splitters, Pipelines y correo.

Respuesta 200
{
  "success": true,
  "run_id": "8f1c2b7e-4d3a-4a91-9c11-2f7b6e0d5a44",
  "status": "completed",
  "flow_id": "3a9d51c0-77b2-4e18-9f6d-0c4a1b8e2d63",
  "flow_name": "Supplier Invoices",
  "source": "api",
  "original_filename": "invoice.pdf",
  "mime_type": "application/pdf",
  "byte_size": 182734,
  "pages_detected": 3,
  "pages_processed": 3,
  "created_at": "2026-09-01T14:02:11Z",
  "started_at": "2026-09-01T14:02:13Z",
  "finished_at": "2026-09-01T14:02:41Z",
  "attempt": 1,
  "previous_attempts": [],
  "error_message": null,
  "data": [
    { "Invoice Number": "001", "Vendor": "Acme Corp", "Total": 270.30 }
  ],
  "columns": null
}
Python (enviar y consultar)
import time
import requests

API_KEY = "YOUR_API_KEY"
HEADERS = {"X-API-Key": API_KEY}

with open("invoice.pdf", "rb") as f:
    submit = requests.post(
        "https://run.tavnit.io/api/runs/process",
        headers=HEADERS,
        data={"flow_id": "YOUR_FLOW_ID"},
        files={"file": f},
    )
run_id = submit.json()["run_id"]

while True:
    run = requests.get(f"https://run.tavnit.io/api/runs/{run_id}", headers=HEADERS).json()
    if run["status"] in ("completed", "failed", "cancelled"):
        break
    time.sleep(5)

print(run["status"], run["data"])

Obtén el documento original

GET/runs/{run_id}/source-file

Devuelve una URL firmada al archivo tal como se subió, sin importar el estado del run. expires_in (opcional) define la vigencia del enlace en segundos (de 60 a 604800; por defecto 7 días). Con ?download=true la respuesta es el archivo en sí.

Respuesta 200
{
  "success": true,
  "kind": "run",
  "run_id": "8f1c2b7e-4d3a-4a91-9c11-2f7b6e0d5a44",
  "original_filename": "invoice.pdf",
  "mime_type": "application/pdf",
  "byte_size": 182734,
  "bucket": "files",
  "path": "<org_id>/<run_id>/invoice.pdf",
  "url": "https://...signed-url...",
  "expires_in": 604800
}

Colecciones: deja que la IA dirija el documento

Envía un documento sin elegir el Flow: la IA escoge el mejor Flow o Splitter de la Colección. Úsalo cuando recibes tipos de documento mezclados.

POST/collections/process

El mismo cuerpo que /runs/process, con collection_id en lugar de flow_id (o pon el ID en la ruta: /collections/{collection_id}/process). La Colección debe estar activa y tener al menos un Flow o Splitter activo; si no, la llamada responde 400.

Python (Colecciones)
import requests

API_KEY = "YOUR_API_KEY"
COLLECTION_ID = "YOUR_COLLECTION_ID"

# ─────────────────────────────────────────────────────────────
# Option 1: Multipart file upload (binary)
# ─────────────────────────────────────────────────────────────
with open("document.pdf", "rb") as file:
    response = requests.post(
        "https://run.tavnit.io/api/collections/process",
        headers={"X-API-Key": API_KEY},
        data={
            "collection_id": COLLECTION_ID,
            "source": "api"
        },
        files={"file": file}
    )

print(response.json())


# ─────────────────────────────────────────────────────────────
# Option 2: Base64-encoded file (JSON body)
# ─────────────────────────────────────────────────────────────
import base64

with open("document.pdf", "rb") as file:
    file_base64 = base64.b64encode(file.read()).decode("utf-8")

response = requests.post(
    "https://run.tavnit.io/api/collections/process",
    headers={
        "X-API-Key": API_KEY,
        "Content-Type": "application/json"
    },
    json={
        "collection_id": COLLECTION_ID,
        "source": "api",
        "filename": "document.pdf",
        "file_base64": file_base64
    }
)

print(response.json())
Respuesta 202
{
  "success": true,
  "data": {
    "collection_run_id": "b21e9f34-8c55-4d70-a6e2-91f0c7d43a18",
    "status": "queued"
  }
}

El Flow elegido crea un run normal, y el payload de su webhook incluye collection_run_id para que relaciones el resultado con tu solicitud. El original está disponible de inmediato en GET /collection-runs/{collection_run_id}/source-file (con las mismas opciones que el archivo original de un run). Consulta Colecciones.

Splitters: divide un archivo con varios documentos

Envía un archivo que contiene varios documentos. El Splitter detecta dónde empieza y termina cada uno, lo clasifica y envía cada parte a donde indique su tipo de documento.

POST/splits/run

El mismo cuerpo que /runs/process, con splitter_id.

Python (Splitters)
import requests

API_KEY = "YOUR_API_KEY"
SPLITTER_ID = "YOUR_SPLITTER_ID"

# ─────────────────────────────────────────────────────────────
# Option 1: Multipart file upload (binary)
# ─────────────────────────────────────────────────────────────
with open("document.pdf", "rb") as file:
    response = requests.post(
        "https://run.tavnit.io/api/splits/run",
        headers={"X-API-Key": API_KEY},
        data={
            "splitter_id": SPLITTER_ID,
            "source": "api"
        },
        files={"file": file}
    )

print(response.json())


# ─────────────────────────────────────────────────────────────
# Option 2: Base64-encoded file (JSON body)
# ─────────────────────────────────────────────────────────────
import base64

with open("document.pdf", "rb") as file:
    file_base64 = base64.b64encode(file.read()).decode("utf-8")

response = requests.post(
    "https://run.tavnit.io/api/splits/run",
    headers={
        "X-API-Key": API_KEY,
        "Content-Type": "application/json"
    },
    json={
        "splitter_id": SPLITTER_ID,
        "source": "api",
        "filename": "document.pdf",
        "file_base64": file_base64
    }
)

print(response.json())
Respuesta 202
{
  "success": true,
  "split_id": "c74a0b12-3e69-4f85-b0d7-58e2a9c61f70",
  "status": "pending",
  "pages_count": 12,
  "message": "Split queued for processing."
}

Las partes enviadas a Flows se convierten en runs propios, y sus webhooks traen split_id. El archivo original completo está en GET /splits/{split_id}/source-file. Consulta Splitters.

Cleaners: ejecuta un sweep

Un sweep pasa un Cleaner por filas de datos para normalizar, clasificar, buscar o enriquecer valores. Envía las filas como hoja de cálculo o como JSON.

POST/sweeps/run
CampoObligatorioDescripción
cleaner_idSíEl Cleaner que se ejecuta.
fileSíCSV, XLSX o XLS, solo multipart. Encabezados en la primera fila; cada campo base que el Cleaner exige debe ser una columna, sin duplicados.
sheet_nameNoQué hoja del libro leer (por defecto, la primera).
POST/cleaners/{cleaner_id}/process

Envía un JSON con rows (un arreglo de objetos), o un file multipart como el de arriba.

Cuerpo JSON
{
  "rows": [
    { "Vendor": "acme corp.", "Country": "usa" },
    { "Vendor": "GLOBEX INC", "Country": "Mexico" }
  ]
}
Python (Cleaners)
import requests

API_KEY = "YOUR_API_KEY"
CLEANER_ID = "YOUR_CLEANER_ID"

# ─────────────────────────────────────────────────────────────
# Option 1: Sweep a spreadsheet (CSV, XLSX or XLS, multipart only)
# Column headers must be on the first row.
# ─────────────────────────────────────────────────────────────
with open("vendors.csv", "rb") as f:
    response = requests.post(
        "https://run.tavnit.io/api/sweeps/run",
        headers={"X-API-Key": API_KEY},
        data={"cleaner_id": CLEANER_ID},
        files={"file": ("vendors.csv", f, "text/csv")},
    )

print(response.json())  # 202: {"sweep_id": "...", "status": "queued", ...}


# ─────────────────────────────────────────────────────────────
# Option 2: Send the rows as JSON
# ─────────────────────────────────────────────────────────────
response = requests.post(
    f"https://run.tavnit.io/api/cleaners/{CLEANER_ID}/process",
    headers={"X-API-Key": API_KEY},
    json={
        "rows": [
            {"Vendor": "acme corp.", "Country": "usa"},
            {"Vendor": "GLOBEX INC", "Country": "Mexico"}
        ]
    },
)

print(response.json())
Respuesta 202
{
  "success": true,
  "sweep_id": "5d2e8a61-0b4f-4c3e-9a7d-1f6b2c8e4a90",
  "status": "queued",
  "cleaner_id": "YOUR_CLEANER_ID",
  "message": "Sweep queued for processing."
}

Un Cleaner con una configuración inválida responde 400 con validation_errors. Consulta Cleaners.

Buckets: escribe y lee filas

Envía filas a un Bucket desde tus propios sistemas, o lee lo que tus Flows guardaron ahí. El ID y el nombre del Bucket aparecen al tocar el ícono de información en su página. El nombre es una verificación de seguridad: si no coincide con el ID, la llamada responde 409.

POST/buckets/write
CampoObligatorioDescripción
bucket_idSíEl Bucket.
bucket_nameSíSu nombre exacto.
overwriteSíBooleano. false agrega las filas; true reemplaza todas las filas existentes.
rowsSíArreglo de objetos, hasta 50,000 por solicitud.

Envía el cuerpo como application/json. Cada fila debe tener exactamente las columnas del Bucket, por nombre de columna o nombre visible: una columna faltante o desconocida cancela toda la escritura con 400 e indica missing_columns y extra_columns.

Python (Buckets)
import requests

API_KEY = "YOUR_API_KEY"
BUCKET_ID = "YOUR_BUCKET_ID"
BUCKET_NAME = "YOUR_BUCKET_NAME"

# ─────────────────────────────────────────────────────────────
# Append rows to existing data (overwrite=False)
# ─────────────────────────────────────────────────────────────
response = requests.post(
    "https://run.tavnit.io/api/buckets/write",
    headers={
        "X-API-Key": API_KEY,
        "Content-Type": "application/json"
    },
    json={
        "bucket_id": BUCKET_ID,
        "bucket_name": BUCKET_NAME,
        "overwrite": False,
        "rows": [
            {"invoice_number": "INV-1001", "vendor": "Acme Corp", "amount": 1200.50},
            {"invoice_number": "INV-1002", "vendor": "Globex", "amount": 430.00}
        ]
    }
)

print(response.json())


# ─────────────────────────────────────────────────────────────
# Replace all rows (overwrite=True)
# ─────────────────────────────────────────────────────────────
response = requests.post(
    "https://run.tavnit.io/api/buckets/write",
    headers={
        "X-API-Key": API_KEY,
        "Content-Type": "application/json"
    },
    json={
        "bucket_id": BUCKET_ID,
        "bucket_name": BUCKET_NAME,
        "overwrite": True,
        "rows": [
            {"invoice_number": "INV-3001", "vendor": "NewCo", "amount": 400.00}
        ]
    }
)

print(response.json())
Respuesta 202
{
  "success": true,
  "message": "Bucket write queued for background processing.",
  "bucket_id": "YOUR_BUCKET_ID",
  "bucket_name": "Invoices 2026",
  "bucket_write_id": "e3a1c9d2-7f40-4b8e-a5c6-2d9f1b0e7a34",
  "overwrite": false,
  "rows_queued": 2,
  "status": "queued"
}

Lee filas

GET/buckets/read

Parámetros de consulta: bucket_id y bucket_name (obligatorios), limit (de 1 a 1000; por defecto 100) y offset (por defecto 0). Avanza con offset mientras has_more sea true; total_count cuenta todas las filas. Las claves de data en cada fila son los nombres de columna; usa columns para los nombres visibles. Los enlaces a archivos guardados llegan como URLs firmadas nuevas.

Solicitud
curl "https://run.tavnit.io/api/buckets/read?bucket_id=YOUR_BUCKET_ID&bucket_name=Invoices%202026&limit=100&offset=0" \
  -H "X-API-Key: YOUR_API_KEY"
Respuesta 200
{
  "success": true,
  "bucket_id": "YOUR_BUCKET_ID",
  "bucket_name": "Invoices 2026",
  "columns": [
    { "name": "invoice_number", "display_name": "Invoice #", "data_type": "text" },
    { "name": "amount", "display_name": "Amount", "data_type": "number" }
  ],
  "rows": [
    {
      "id": "0c6f...",
      "row_number": 1,
      "source_type": "api",
      "created_at": "2026-09-01T14:05:00Z",
      "updated_at": "2026-09-01T14:05:00Z",
      "data": { "invoice_number": "INV-1001", "amount": 1200.5 }
    }
  ],
  "total_count": 1234,
  "limit": 100,
  "offset": 0,
  "has_more": true
}

Consulta Buckets.

Agentes: inicia y consulta runs

Inicia un Agente desde tu código y recoge lo que capturó. Los Agentes se habilitan por organización a pedido: contacta a soporte para activarlos.

POST/bots/{agent_id}/runs

El JSON opcional {"inputs": {...}} reemplaza las variables de entrada del Agente para este run. Solo se usan las variables que el Agente declara, y nunca se aceptan valores secretos. También puedes llamar a POST /bots/runs con bot_id en el cuerpo. Cada llamada inicia un run nuevo.

Solicitud
curl -X POST "https://run.tavnit.io/api/bots/YOUR_AGENT_ID/runs" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"inputs": {"invoice_month": "2026-08"}}'

# 202
{ "success": true, "bot_run_id": "a7c3...", "status": "queued" }

status es queued, o waiting cuando el Agente ejecuta un run a la vez y está ocupado (empieza solo cuando le llega el turno). 409 si el Agente está archivado, 429 si ya hay demasiados runs esperando.

Consulta, lista y cancela

EndpointQué hace
GET /bot-runs/{bot_run_id}Un run: estado, tiempos, input (sin secretos) y output con enlaces firmados a archivos. También en GET /bots/{agent_id}/runs/{bot_run_id}.
GET /bots/{agent_id}/runsDel más reciente al más antiguo, sin input ni output. Consulta: status (queued, running, completed, failed, cancelled), limit (de 1 a 100; por defecto 20), offset. Devuelve runs y total.
POST /bot-runs/{bot_run_id}/cancelCancela un run en espera, en cola o en ejecución. 409 si el run ya terminó. También en POST /bots/{agent_id}/runs/{bot_run_id}/cancel.
GET /bot-runs/{bot_run_id}
{
  "success": true,
  "run": {
    "id": "a7c3...",
    "bot_id": "YOUR_AGENT_ID",
    "status": "completed",
    "source": "api",
    "created_at": "2026-09-01T09:00:00Z",
    "started_at": "2026-09-01T09:00:04Z",
    "finished_at": "2026-09-01T09:03:10Z",
    "duration_seconds": 186,
    "llm_requests": 9,
    "error_message": null,
    "replay_url": "https://...",
    "input": { "invoice_month": "2026-08" },
    "output": { "...": "what the agent captured, file links signed" }
  }
}

Consulta Agentes.

Matchers: compara runs

Compara runs completados del Flow del Matcher, por ejemplo facturas contra órdenes de compra.

POST/matchers/{matcher_id}/run
CampoObligatorioDescripción
run_idsSíDos o más runs completados del Flow del Matcher.
benchmark_run_idEn modo benchmarkEl run contra el que se comparan los demás.
Solicitud
curl -X POST "https://run.tavnit.io/api/matchers/YOUR_MATCHER_ID/run" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"run_ids": ["RUN_A", "RUN_B"], "benchmark_run_id": "RUN_A"}'

# 202
{
  "success": true,
  "match_id": "...",
  "status": "queued",
  "mode": "benchmark",
  "run_ids": ["RUN_A", "RUN_B"]
}

No hay un endpoint de API para leer un match: recibe el resultado en el webhook o la salida por correo del Matcher, o en la app. Consulta Matchers.

Inspectores: revisa un conjunto de documentos

Una inspección reúne documentos, dirige cada uno a un espacio del Inspector, lo extrae y evalúa la lista de verificación.

POST/inspectors/{inspector_id}/process

file multipart. Sin inspection_id se crea una inspección nueva; envía el inspection_id devuelto para agregarle más documentos (debe seguir recibiendo archivos; si no, 409). El Inspector debe estar activo.

Solicitud
curl -X POST "https://run.tavnit.io/api/inspectors/YOUR_INSPECTOR_ID/process" \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "file=@bill_of_lading.pdf"

# 202 — send the next files with -F "inspection_id=..."
{
  "success": true,
  "inspection_id": "...",
  "inspection_file_id": "...",
  "status": "queued"
}
EndpointQué hace
POST /inspectors/{inspector_id}/inspectionsCrea una inspección vacía (201) para agregarle documentos después.
POST /inspections/{inspection_id}/fireDeja de recibir archivos y evalúa ahora. 400 con missing_inputs si a un espacio obligatorio le falta documento.

El resultado llega al webhook o a la salida por correo del Inspector. Consulta Inspectores.

Fillers: llena formularios PDF

Un fill reúne los documentos que necesita un Filler, los extrae y escribe los valores en las plantillas PDF del Filler.

EndpointQué hace
POST /fillers/{filler_id}/fillsAbre un fill (201, devuelve fill_id). El Filler necesita una plantilla y el mapeo de campos.
POST /fills/{fill_id}/route-uploadArchivo multipart; la IA lo dirige a un espacio libre (202).
POST /fills/{fill_id}/inputs/{input_id}/uploadArchivo multipart para un espacio concreto; inicia el run de ese espacio (202).
POST /fills/{fill_id}/inputs/{input_id}/attach-runJSON run_id: reutiliza un run completado para un espacio (202).
POST /fills/{fill_id}/fireLlena ahora en lugar de esperar todos los espacios. 400 con missing_inputs si un espacio obligatorio está vacío.
POST /fillers/{filler_id}/templatesAgrega una plantilla PDF (archivo multipart, name opcional). Mapea sus campos en la app.
Solicitud
# 1. Open a fill (201)
curl -X POST "https://run.tavnit.io/api/fillers/YOUR_FILLER_ID/fills" \
  -H "X-API-Key: YOUR_API_KEY"

# 2. Upload documents and let AI pick the slot (202)
curl -X POST "https://run.tavnit.io/api/fills/FILL_ID/route-upload" \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "file=@passport.jpg"

# 3. Optional: fill now instead of waiting for every slot (202)
curl -X POST "https://run.tavnit.io/api/fills/FILL_ID/fire" \
  -H "X-API-Key: YOUR_API_KEY"

Los PDF llenos llegan al webhook o a la salida por correo del Filler. Consulta Fillers.

Pipelines: ejecuta

Inicia una ejecución de un Pipeline con un documento.

POST/pipelines/{pipeline_id}/execute

file multipart o file_base64 + filename; PDF o imagen. 400 si el Pipeline está inactivo o su grafo no puede ejecutarse (con validation_errors).

Solicitud
curl -X POST "https://run.tavnit.io/api/pipelines/YOUR_PIPELINE_ID/execute" \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "file=@invoice.pdf"

# 202
{
  "success": true,
  "execution_id": "...",
  "pipeline_id": "YOUR_PIPELINE_ID",
  "status": "running"
}

Cancela con POST /pipelines/executions/{execution_id}/cancel (409 si no está en ejecución). Los resultados salen por los nodos Salida del Pipeline. Consulta Pipelines.

Signals: estructura un archivo de audio

Envía una grabación y el Signal la convierte en datos estructurados (una Wave).

POST/signals/{signal_id}/run

file multipart o base64. Audio de hasta 150 MB y 8 horas, con un máximo de 2 horas de voz detectada.

Solicitud
curl -X POST "https://run.tavnit.io/api/signals/YOUR_SIGNAL_ID/run" \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "file=@sales_call.mp3"

# 202
{
  "success": true,
  "wave_id": "...",
  "signal_id": "YOUR_SIGNAL_ID",
  "status": "queued",
  "audio_seconds": 754,
  "auto_created_wave": true
}

El resultado llega al webhook del Signal o a la app. Consulta Signals.

Subjects y casos

Archiva documentos en los casos de un Subject y gestiona los casos desde tu código.

EndpointQué hace
POST /subjects/{subject_id}/processArchivo multipart; Tavnit lo dirige a un caso (202, devuelve subject_doc_id).
POST /cases/{case_id}/docsArchivo multipart directo a un caso, sin enrutamiento. doc_type_id es obligatorio salvo que el Subject tenga un solo tipo de documento. Devuelve el run_id (202). 409 si el caso está cerrado o ese tipo de documento ya está cubierto.
POST /subjects/{subject_id}/docs/{doc_id}/assignJSON case_id y doc_type_id: archiva a mano un documento retenido (202).
POST /subjects/{subject_id}/casesJSON name (obligatorio, único, hasta 200 caracteres) y params (objeto opcional). Crea un caso (201). 409 si el nombre ya existe.
GET /subjects/{subject_id}/casesConsulta: state (open o closed), status, search, limit (hasta 200; por defecto 50), offset. Devuelve cases y total.
GET /cases/{case_id}El caso y sus documentos, cada uno con el run_id para consultar en GET /runs/{run_id}.
POST /cases/{case_id}/closeCierra el caso (200). Los documentos nuevos para él quedan retenidos en lugar de archivarse. 409 si ya está cerrado.
POST /cases/{case_id}/reopenLo reabre (200). 409 si está abierto.
POST /cases/{case_id}/inspectionsJSON subject_inspector_id: ejecuta un Inspector vinculado sobre los runs completados del caso (202).
Solicitud
# Create a case (201)
curl -X POST "https://run.tavnit.io/api/subjects/YOUR_SUBJECT_ID/cases" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Shipment 4471", "params": {"customer": "Acme"}}'

# Upload a document straight into that case (202)
curl -X POST "https://run.tavnit.io/api/cases/CASE_ID/docs" \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "file=@invoice.pdf" \
  -F "doc_type_id=DOC_TYPE_ID"
Respuesta 201
{
  "success": true,
  "case": {
    "id": "...",
    "subject_id": "YOUR_SUBJECT_ID",
    "ref": "<minted from the subject's prefix>",
    "seq": 42,
    "name": "Shipment 4471",
    "state": "open",
    "status": "<the subject's default case status>",
    "params": { "customer": "Acme" },
    "created_by": "...",
    "created_at": "2026-09-01T10:00:00Z",
    "updated_at": "2026-09-01T10:00:00Z",
    "closed_at": null,
    "closed_by": null
  }
}

Consulta Subjects.

Nets: inicia un Catch

Las Nets se habilitan por organización. Sin acceso, estos endpoints responden 403.

POST/nets/{net_id}/catch

Sin cuerpo, el Catch continúa donde terminó el anterior. Envía window_start y/o window_end (fechas ISO) para recuperar un rango específico. 409 si la Net está inactiva o ya hay en curso un Catch que continúa desde el anterior.

Solicitud
curl -X POST "https://run.tavnit.io/api/nets/YOUR_NET_ID/catch" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

# 202
{ "success": true, "catch_id": "...", "net_id": "YOUR_NET_ID", "status": "queued", "window_mode": "since_last" }

Consulta GET /catches/{catch_id}: estado, etapa, conteos y, una vez completado, output con columnas y filas. Cancela con POST /catches/{catch_id}/cancel. Consulta Nets.

Revisión Humana: aprueba o rechaza

Los elementos en pausa para revisión se pueden aprobar o rechazar desde tus propias herramientas. Solo puede hacerlo un revisor configurado de ese Flow, Matcher, Inspector o Filler (si no, 403), y el elemento debe estar en awaiting_approval (si no, 409). Estos endpoints están abiertos al rol Solo HITL.

EndpointCuerpo
POST /runs/{run_id}/hitl/approveoutput_json (obligatorio): las filas finales; diff (lista opcional de ediciones). 400 con missing_fields si falta un campo obligatorio de entrada humana.
POST /matches/{match_id}/hitl/approvegroups (la agrupación final), excluded, diff.
POST /inspections/{inspection_id}/hitl/approvewaivers (item_id y reason de cada punto fallido que se dispensa), diff.
POST /fills/{fill_id}/hitl/approvevalues (valores de campos por plantilla), diff, allow_missing_human_fields.
.../hitl/rejectLas mismas rutas terminadas en /hitl/reject, con un reason opcional.
Solicitud
curl -X POST "https://run.tavnit.io/api/runs/RUN_ID/hitl/approve" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"output_json": {"rows": [{"Invoice Number": "001", "Total": 270.30}]}, "diff": []}'

curl -X POST "https://run.tavnit.io/api/runs/RUN_ID/hitl/reject" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Wrong vendor"}'

Aprobar reanuda la entrega (webhook, correo, Bucket). Rechazar un run lo cancela. Consulta Revisión Humana.

Endpoints de la API key

EndpointQué hace
GET /me/api-keyDevuelve tu key para la organización.
POST /me/api-key/regenerateEmite una key nueva e invalida la anterior al instante. Actualiza todas tus integraciones.
Respuesta 200
{
  "success": true,
  "api_key": "tvnt_...",
  "user_id": "...",
  "org_id": "..."
}