Saptiva Document Extraction API
La API de Extracción de Documentos de Saptiva permite subir documentos PDF para extracción de datos potenciada por IA. Soporta cuatro tipos de documentos: Contratos, Pólizas de Seguro, Fianzas y Actas Constitutivas.
Base URL
https://adjudicator.saptiva.comAutenticación
Todos los endpoints requieren autenticación mediante API key a través del header Authorization.
Authorization: Token <sk-saptiva-your_api_key>
Errores
La API utiliza códigos de estado HTTP convencionales para indicar el éxito o fracaso de una petición. Todas las respuestas de error incluyen un mensaje legible (error) y un código máquina (code).
{
"error": "Mensaje de error legible",
"code": "ERROR_CODE"
}| HTTP | Código | Descripción |
|---|---|---|
400 | MISSING_FIELDS | Campos requeridos faltantes |
400 | INVALID_DOCUMENT_TYPE | tipo_documento debe ser 1, 2, 3 o 4 |
400 | INVALID_FILE_FORMAT | Solo se aceptan archivos PDF |
400 | FILE_TOO_LARGE | El archivo excede el límite de tamaño |
400 | PDF_CORRUPTED | PDF corrupto, sin páginas o estructura ilegible |
400 | TEXT_EXTRACTION_FAILED | No se pudo extraer texto del documento |
401 | AUTH_MISSING_HEADER | Falta el header Authorization |
401 | AUTH_INVALID_FORMAT | Formato inválido (debe ser: Token <key>) |
401 | AUTH_EMPTY_KEY | API key vacía |
401 | AUTH_INVALID_KEY | API key inválida o inactiva |
404 | JOB_NOT_FOUND | Job no encontrado |
409 | DUPLICATE_DOCUMENT | Ya existe documento con mismo expediente_id + documento_id |
500 | OCR_START_FAILED | Falló al iniciar procesamiento OCR |
500 | INTERNAL_ERROR | Error interno del servidor |
Error de PDF Corrupto (400)
Se retorna cuando el archivo PDF está dañado o es ilegible. El archivo no se sube al almacenamiento y no se crea un registro de job.
{
"error": "Archivo PDF corrupto: PDF file has no pages or structure is corrupted",
"code": "PDF_CORRUPTED"
}Posibles errores de validación:
PDF has no readable pages- El PDF tiene 0 páginas legiblesPDF structure is invalid- La estructura interna del PDF no se puede parsearPDF pages cannot be read- Las páginas existen pero el contenido es inaccesiblePDF file is corrupted or unreadable- Corrupción general detectada
Webhook de error:
Si se proporcionó webhook_url, se envía un webhook de error con id igual a documento_id (no tracker_id, ya que no se crea un job):
{
"exitoso": false,
"id": "DOC-001",
"tipo_documento": 1,
"texto_extraido": null,
"datos_extraidos": null,
"mensaje": "Archivo PDF corrupto: PDF file has no pages or structure is corrupted",
"code": "PDF_CORRUPTED"
}Extracción
/api/extract/Extraer documento
Sube un documento PDF para extracción. El contenido debe ser multipart/form-data.
Parámetros de Request
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
documento_id | string | Sí | Tu ID interno de seguimiento del documento |
expediente_id | string | Sí | ID del caso/expediente al que pertenece el documento |
documento | file | Sí | Archivo PDF a procesar |
webhook_url | string | No | URL para recibir resultados vía PUT. Si se omite, usar GET para obtener resultados. |
tipo_documento | number | Sí | 1=Contrato, 2=Seguro, 3=Fianza, 4=Acta Constitutiva |
/api/extract/{tracker_id}Obtener resultado
Recupera el estado y resultados de un job de extracción. Útil si tu webhook falló o para consultar el estado.
Valores de Status
| Status | Descripción |
|---|---|
received | Job creado, procesamiento no iniciado |
ocr_processing | Esperando OCR de DocumentAI |
llm_processing | Ejecutando extracción LLM |
completed | Procesado exitosamente |
webhook_failed | Procesado pero falló la entrega del webhook |
error | El procesamiento falló |
/api/extract/reprocessReprocesar documento
Re-ejecuta la extracción LLM en un documento previamente subido. El contenido debe ser application/json.
Request Body
{
"tracker_id": "saptiva_1704825600000_abc123"
}/api/extract/jobsListar jobs
Lista todos los jobs de extracción para la API key autenticada. Útil para obtener tracker IDs y consultar resultados.
Respuesta
| Campo | Descripción |
|---|---|
jobs | Array de jobs con tracker_id, status, documento_id, etc. |
total | Número total de jobs |
/api/extract/usageObtener uso
Obtiene estadísticas de uso para la API key autenticada. Útil para facturación y seguimiento.
Campos de Respuesta
| Campo | Descripción |
|---|---|
total_pages | Suma de todas las páginas procesadas (incluye reprocesamiento) |
total_processing_events | Número total de eventos de procesamiento |
unique_documents | Número de documentos únicos procesados |
documents | Array con detalles de cada documento y su processing_count |
Webhook Callback
Cuando el procesamiento se completa (sync o async), se envía un request PUT a tu webhook_url.
Payload de Éxito
{
"exitoso": true,
"id": "saptiva_1704825600000_abc123",
"tipo_documento": 1,
"texto_extraido": "CONTRATO DE SERVICIOS COMERCIALES...\nCLÁUSULA PRIMERA...",
"datos_extraidos": {
"numero_contrato": {
"value": "AIFA-DCS-SSC-GSC-001-2025",
"certainty": 1.0
},
"nombre_contraparte": {
"value": "Empresa ABC S.A. de C.V.",
"certainty": 1.0
},
"rfc_contraparte": {
"value": "EAB123456XX0",
"certainty": 0.8
},
"monto_afianzado": {
"value": {
"monto": 1500000,
"porcentaje_aplicado": 10,
"base_calculo": "10% del monto total del contrato",
"moneda": "MXN"
},
"certainty": 1.0
},
"errors": {
"hasError": false,
"errorMessage": ""
}
},
"mensaje": "Documento procesado exitosamente"
}Payload de Error
{
"exitoso": false,
"id": "saptiva_1704825600000_abc123",
"tipo_documento": 1,
"texto_extraido": null,
"datos_extraidos": null,
"mensaje": "Error procesando documento: No text extracted from document",
"code": "TEXT_EXTRACTION_FAILED"
}Códigos de error en webhooks: El campo code contiene los mismos códigos listados en la tabla de errores (ej. PDF_CORRUPTED, TEXT_EXTRACTION_FAILED, OCR_START_FAILED, INTERNAL_ERROR).
Tipos de Documento
Contrato (AIFA)
Contratos del Aeropuerto Internacional Felipe Ángeles. Detecta automáticamente el tipo de contrato según el patrón del número:
AIFA-DCS-SSC-GSC-XXX-YYYYServicios Comerciales
AIFA-DCS-SMC-...Movilidad
AIFA-DCS-SSAC-...Servicios Aeroportuarios
AIFA-C-[LPN|ITP|AD]-...Recursos Materiales
Campos Extraídos
tipo_contrato_detectadoTipo de contrato detectadonumero_contratoNúmero completo del contratodesglose_numero_contratoDesglose (entidad, dirección, subdirección, etc.)tipo_contratoTipo (arrendamiento, prestación de servicios, etc.)nombre_aeropuertoAeropuerto Internacional Felipe Ángeles, S.A. de C.V.rfc_aeropuertoAIF2101127VAnombre_contraparteNombre de la contraparterfc_contraparteRFC de la contraparterol_contraparteRol (arrendatario, prestador, proveedor, transportista)clausula_objetoCláusula del objeto del contratoclausula_uso_destinoCláusula de uso exclusivoespacio_arrendadoEspacio (metros, ubicación, nomenclatura)vigenciaDuración (fecha_inicio, fecha_termino, años)importeDetalles (renta_mensual, contraprestación, monto_contrato)cuota_serviciosCuota de servicios (porcentaje)clausula_garantia_fianzaCláusula de garantía/fianzamonto_afianzadoMonto (monto, porcentaje, base_calculo, moneda)declaraciones_fianzaRequisitos de póliza de fianza (array)naturaleza_obligacionesDivisible/indivisibleclausula_seguroCláusula de segurodeclaraciones_seguroRequisitos de póliza de seguro (array)jurisdiccionJurisdicción (para Recursos Materiales)fecha_firmaFecha de firmaSeguro
Pólizas de seguro para AIFA.
Campos Extraídos
numero_polizaNúmero de póliza (numérico o alfanumérico)nombre_aseguradoNombre del asegurado (puede ser empresa matriz o subsidiaria)vigenciaPeríodo de cobertura (fecha_inicio, fecha_fin, descripcion)ubicacion_riesgoUbicación del riesgo (dirección del aeropuerto)coberturasArray de coberturas (tipo, descripcion, suma_asegurada, deducible)clausula_beneficiarioCláusula del beneficiario (nombre_beneficiario, descripcion)clausulas_polizaCláusulas de la póliza del contrato (array)aseguradoraNombre de la compañía aseguradoraFianza
Fianzas de garantía para contratos AIFA.
Campos Extraídos
numero_fianzaNúmero de fianza (puede estar ausente en borradores)nombre_fiadoNombre del fiado/contrapartenombre_beneficiarioNombre del beneficiario (típicamente AIFA)entidad_contratoEntidad que genera el contratodomicilio_beneficiarioDirección del beneficiario (opcional)numero_contratoNúmero del contrato garantizadofecha_contratoFecha de firma del contratorevision_objetoRevisión del objeto (tipo_contrato, descripcion, dimensiones, nomenclatura)vigenciaPeríodo de validez (fecha_inicio, fecha_fin, descripcion)monto_afianzadoMonto afianzado (monto, moneda, descripcion)declaracionesDeclaraciones de la fianza (array)afianzadoraNombre de la compañía afianzadoratipo_fianzaTipo (cumplimiento, anticipo, vicios ocultos, fidelidad, etc.)Acta Constitutiva
Actas constitutivas (documentos de constitución de empresas) emitidas por notarios mexicanos.
Campos Extraídos
fecha_constitucionFecha de constitución de la empresa (DD-MM-YYYY)razon_socialRazón social incluyendo tipo societario (S.A. de C.V., S. de R.L., etc.)poderes_administracionLista de personas con poderes de administración (array)poderes_dominioLista de personas con poderes de dominio (array)ambos_poderesLista de personas con ambos poderes (administración y dominio)lista_accionistasLista de todos los accionistas (array)participacion_accionariaPorcentajes de participación por accionista (array: "Nombre: Porcentaje%")clausula_exclusion_extranjerosCláusula de exclusión de extranjeros: "True" (excluye), "False" (permite), "Null" (sin cláusula)Formato de Datos
Fechas
Todas las fechas se devuelven en formato DD-MM-YYYY.
Montos
Los montos monetarios se devuelven como números (no como strings).
Certainty Scores
Cada campo extraído incluye un score de certainty de 0.0 a 1.0 indicando el nivel de confianza:
1.0Encontrado explícitamente en el documento0.8Inferido con alta confianza0.5Incierto/coincidencia parcial0.0No encontrado en el documentoTexto Extraído
El campo texto_extraido contiene el texto completo del documento como texto plano.
Límites
100MB30 segundosEjemplos de Integración
Cliente Python
import requests
API_KEY = "sk-saptiva-your-key-here"
BASE_URL = "https://adjudicator.saptiva.com"
def extract_document(pdf_path, documento_id, expediente_id, tipo_documento, webhook_url):
with open(pdf_path, 'rb') as f:
response = requests.post(
f"{BASE_URL}/api/extract/",
headers={"Authorization": f"Token {API_KEY}"},
files={"documento": f},
data={
"documento_id": documento_id,
"expediente_id": expediente_id,
"tipo_documento": tipo_documento,
"webhook_url": webhook_url
}
)
return response.json()
# Subir un contrato
result = extract_document(
pdf_path="contract.pdf",
documento_id="DOC-001",
expediente_id="EXP-2026-001",
tipo_documento=1, # Contrato
webhook_url="https://my-server.com/webhook"
)
print(f"Tracker ID: {result['tracker_id']}")
# Subir un acta constitutiva
result = extract_document(
pdf_path="acta_constitutiva.pdf",
documento_id="DOC-002",
expediente_id="EXP-2026-001",
tipo_documento=4, # Acta Constitutiva
webhook_url="https://my-server.com/webhook"
)
print(f"Tracker ID: {result['tracker_id']}")Receptor de Webhook (Flask)
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhook/receive', methods=['PUT'])
def receive_webhook():
data = request.json
if data.get('exitoso'):
tracker_id = data['id']
tipo = data['tipo_documento']
extracted = data['datos_extraidos']
# Procesar los datos extraídos
print(f"Documento {tracker_id} procesado exitosamente")
print(f"Campos extraídos: {list(extracted.keys())}")
else:
print(f"Procesamiento fallido: {data['mensaje']}")
return jsonify({"status": "received"}), 200
if __name__ == '__main__':
app.run(port=5001)