Saptiva|API Reference

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.com

Autenticación

Todos los endpoints requieren autenticación mediante API key a través del header Authorization.

Header de autenticación
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).

Formato de respuesta de error
{
  "error": "Mensaje de error legible",
  "code": "ERROR_CODE"
}
HTTPCódigoDescripción
400FILE_TOO_LARGEEl archivo excede el límite de tamaño
400INVALID_DOCUMENT_TYPEtipo_documento debe ser 1, 2, 3 o 4
400INVALID_FILE_FORMATSolo se aceptan archivos PDF
400MISSING_FIELDSCampos requeridos faltantes
400MISSING_TRACKER_IDtracker_id no proporcionado
400NO_TEXT_AVAILABLENo hay texto extraído disponible para reprocesar
400PDF_CORRUPTEDPDF corrupto, sin páginas o estructura ilegible
400PDF_TOO_MANY_PAGESEl documento excede el límite de 100 páginas (tope rígido aplicado a toda solicitud)
400TEXT_EXTRACTION_FAILEDNo se pudo extraer texto del documento
401ALLOWANCE_EXCEEDEDAPI key ya alcanzó su límite de páginas
401AUTH_EMPTY_KEYAPI key vacía
401AUTH_INVALID_FORMATFormato inválido (debe ser: Token <key>)
401AUTH_INVALID_KEYAPI key inválida o inactiva
401AUTH_MISSING_HEADERFalta el header Authorization
402ALLOWANCE_WOULD_EXCEEDProcesar este documento excedería el límite de páginas
404JOB_NOT_FOUNDJob no encontrado
409DUPLICATE_DOCUMENTYa existe documento con mismo expediente_id + documento_id
500INTERNAL_ERRORError interno del servidor
500OCR_START_FAILEDFalló al iniciar procesamiento OCR

Errores de la puerta de enlace

Estos errores los devuelve directamente la puerta de enlace de la API de Saptiva y no incluyen el campo code:

400 — webhook_url inválido
{
  "error": "Invalid webhook_url: must be a valid HTTPS URL"
}
502 — No fue posible completar la solicitud
{
  "error": "Saptiva API Proxy error",
  "message": "..."
}

Cada respuesta incluye el header X-Request-Id. Compártelo con soporte al reportar un problema.

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.

Respuesta de error
{
  "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 legibles
  • PDF structure is invalid - La estructura interna del PDF no se puede parsear
  • PDF pages cannot be read - Las páginas existen pero el contenido es inaccesible
  • PDF file is corrupted or unreadable - Corrupción general detectada

Los errores que se devuelven directamente en la respuesta HTTP (4xx) no generan webhook, ya que no se crea un job. Manéjalos a partir de la respuesta.

Extracción

POST/api/extract/

Extraer documento

Sube un documento PDF para extracción. El contenido debe ser multipart/form-data.

Parámetros de Request

CampoTipoRequeridoDescripción
documento_idstringSíTu ID interno de seguimiento del documento
expediente_idstringSíID del caso/expediente al que pertenece el documento
documentofileSíArchivo PDF a procesar (máximo 100 páginas)
webhook_urlstringNoURL HTTPS pública para recibir resultados vía PUT (ver Webhook Callback). Si se omite, usar GET para obtener resultados.
tipo_documentonumberSí1=Contrato, 2=Seguro, 3=Fianza, 4=Acta Constitutiva

El webhook_url debe usar HTTPS y apuntar a un host público: no se aceptan localhost, IPs privadas ni el dominio de esta API. Si no cumple, la solicitud se rechaza antes de procesarse (sin campo code):

400 {"error": "Invalid webhook_url: must be a valid HTTPS URL"}

Respuestas

202 Accepted — PDF escaneado, OCR iniciado
{
  "message": "Documento recibido, procesamiento OCR iniciado",
  "tracker_id": "saptiva_1704825600000_abc123"
}
200 OK — PDF legible, procesado inmediatamente
{
  "message": "Documento procesado exitosamente",
  "tracker_id": "saptiva_1704825600000_abc123"
}
GET/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

StatusDescripción
receivedJob creado, procesamiento no iniciado
ocr_processingEsperando OCR de DocumentAI
llm_processingEjecutando extracción LLM
completedProcesado exitosamente
webhook_failedProcesado pero falló la entrega del webhook
errorEl procesamiento falló

Respuesta — Completado (200)

JSON
{
  "tracker_id": "saptiva_1704825600000_abc123",
  "status": "completed",
  "exitoso": true,
  "tipo_documento": 1,
  "documento_id": "DOC-001",
  "expediente_id": "EXP-2026-001",
  "created_at": 1704825600000,
  "updated_at": 1704825650000,
  "page_count": 15,
  "datos_extraidos": {
    "numero_contrato": { "value": "ENT-DCS-SSC-GSC-001-2025", "certainty": 1.0 },
    "nombre_contraparte": { "value": "Empresa ABC S.A. de C.V.", "certainty": 1.0 }
  },
  "texto_extraido": "CONTRATO DE SERVICIOS COMERCIALES...",
  "mensaje": "Documento procesado exitosamente"
}
HTTPCódigoDescripción
401AUTH_*API key faltante o inválida
404JOB_NOT_FOUNDNo existe job con ese tracker_id
500INTERNAL_ERRORError interno del servidor
POST/api/extract/reprocess

Reprocesar documento

Re-ejecuta la extracción LLM en un documento previamente subido. El contenido debe ser application/json.

Request Body

JSON
{
  "tracker_id": "saptiva_1704825600000_abc123"
}

Respuestas de Error

HTTPCódigoDescripción
400MISSING_TRACKER_IDtracker_id no proporcionado
400NO_TEXT_AVAILABLENo hay texto extraído disponible para reprocesar
401AUTH_*API key faltante o inválida
404JOB_NOT_FOUNDNo existe job con ese tracker_id
500INTERNAL_ERRORError interno del servidor
GET/api/extract/jobs

Listar jobs

Lista todos los jobs de extracción para la API key autenticada. Útil para obtener tracker IDs y consultar resultados.

Respuesta

CampoDescripción
jobsArray de jobs con tracker_id, status, documento_id, expediente_id, tipo_documento, page_count, created_at y updated_at
totalNúmero total de jobs
GET/api/extract/usage

Obtener uso

Obtiene estadísticas de uso para la API key autenticada. Útil para facturación y seguimiento.

Campos de Respuesta

CampoDescripción
processed_pagesTotal de páginas procesadas (incluye reprocesamiento)
allowanceLímite de páginas para esta API key (null = ilimitado)
remaining_pagesPáginas restantes antes del límite (null = ilimitado)
total_eventsNúmero total de eventos de procesamiento
unique_documentsNúmero de documentos únicos procesados
documentsArray 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.

Requisitos

  • El webhook_url debe usar HTTPS y apuntar a un host público (no se aceptan localhost, IPs privadas ni el dominio de esta API).
  • Tu endpoint debe responder con un status 2xx; cualquier otra respuesta se considera una entrega fallida.
  • El campo id del payload es el tracker_id del job.
  • Tu webhook_url se conserva 30 días. Si reprocesas el documento dentro de ese plazo, se vuelve a notificar al mismo URL; después, consulta el resultado con GET /api/extract/{tracker_id}.

Payload de Éxito

PUT webhook_url
{
  "exitoso": true,
  "id": "saptiva_1704825600000_abc123",
  "tipo_documento": 1,
  "texto_extraido": "CONTRATO DE SERVICIOS COMERCIALES...\nCLÁUSULA PRIMERA...",
  "datos_extraidos": {
    "numero_contrato": {
      "value": "GAFSACOMM-0001-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

PUT webhook_url
{
  "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. TEXT_EXTRACTION_FAILED, OCR_START_FAILED, INTERNAL_ERROR).

Tipos de Documento

tipo_documento = 1

Contrato

Contratos comerciales y de servicios. Detecta automáticamente el tipo de contrato y extrae información relevante.

Campos Extraídos

tipo_contrato_detectadoTipo de contrato detectado (SERVICIOS_COMERCIALES, MOVILIDAD, SERVICIOS_AEROPORTUARIOS, RECURSOS_MATERIALES)
numero_contratoNúmero principal del contrato, extraído verbatim (preserva guiones, casing, ceros a la izquierda)
tipo_contratoTipo (arrendamiento, prestación de servicios, adquisición, etc.)
nombre_beneficiarioNombre o razón social de la entidad contratante/beneficiario
rfc_beneficiarioRFC de la entidad contratante/beneficiario
nombre_contraparteNombre de la contraparte
rfc_contraparteRFC de la contraparte
rol_contraparteRol (arrendatario, prestador, proveedor, transportista)
clausula_objetoCláusula del objeto del contrato
clausula_uso_destinoCláusula de uso exclusivo
espacio_arrendadoEspacio (metros, ubicación, nomenclatura)
vigenciaDuración (fecha_inicio, fecha_termino, años)
importeDetalles (renta_mensual, contraprestación, monto_contrato)
cuota_serviciosCuota de mantenimiento (porcentaje, descripcion)
garantiasArray de garantías (tipo, descripcion, ubicacion, mecanismo, requiere_fianza, monto, porcentaje_aplicado, base_calculo, moneda, vigencia_descripcion, requisitos)
naturaleza_obligacionesDivisible/indivisible
clausula_seguroRequisitos de seguro o responsabilidad civil (descripcion, ubicacion)
declaraciones_seguroRequisitos de póliza de seguro (array)
jurisdiccionJurisdicción (para Recursos Materiales)
fecha_firmaFecha de firma
tipo_documento = 2

Seguro

Pólizas de seguro.

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
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 aseguradora
tipo_documento = 3

Fianza

Fianzas de garantía para contratos. Soporta formatos gubernamentales (RM, LAASSP, LOPSRM) y múltiples monedas.

Campos Extraídos

numero_fianzaNúmero de la póliza de fianza (puede estar ausente en borradores)
nombre_fiadoRazón social del fiado/contraparte
rfc_fiadoRFC del fiado/proveedor
domicilio_fiadoDomicilio del fiado (debe coincidir con el del contrato principal)
nombre_beneficiarioNombre del beneficiario
entidad_obligacionEntidad ante quien se garantiza la obligación
domicilio_beneficiarioDomicilio del beneficiario (opcional)
medio_electronico_envioMedio electrónico (correo, portal) para envío de la fianza a la Contratante/Beneficiaria
numero_referenciaIdentificador del documento base (contrato, expediente judicial o crédito fiscal)
fecha_documento_baseFecha del contrato, resolución judicial o crédito fiscal
objeto_afianzadoObjeto garantizado (tipo, descripcion, datos_adicionales)
vigenciaVigencia de la fianza (fecha_inicio, fecha_fin, descripcion)
monto_afianzadoMonto afianzado (monto, monto_letra, moneda [MXN/USD/EUR/OTRO], descripcion)
monto_contrato_garantizadoValor total del contrato sin IVA (numérico)
monto_letra_contrato_garantizadoMonto del contrato escrito con letra (sin IVA)
moneda_contrato_garantizadoCódigo ISO de la moneda del contrato (MXN, USD, EUR, OTRO)
tipo_obligacion_garantizadaTipo de obligación garantizada (ADQUISICIONES, ARRENDAMIENTOS, SERVICIOS, OBRA_PUBLICA, SERVICIOS_RELACIONADOS_OP, OTRO)
naturaleza_obligacionesDivisible o indivisible, conforme al contrato
procedimiento_efectividadArtículo y ley aplicable para hacer efectiva la fianza (ej: art. 279 LISF)
competencia_jurisdiccionTribunales y lugar de jurisdicción
costosCostos de la fianza (prima_neta, gastos, subtotal, iva, prima_total)
fecha_expedicionFecha de expedición/emisión de la fianza
fecha_suscripcionFecha de suscripción/firma de la fianza
declaracionesDeclaraciones plasmadas en la fianza (array)
afianzadoraNombre de la compañía afianzadora/aseguradora
domicilio_afianzadoraDomicilio de la institución afianzadora
numero_oficio_autorizacion_afianzadoraNúmero de oficio de autorización del Gobierno Federal para operar
fecha_autorizacion_afianzadoraFecha de la autorización del Gobierno Federal
representante_afianzadoraNombre del representante de la afianzadora que firma la póliza
validacion_urlURL del portal de validación de la fianza
tipo_fianzaTipo (cumplimiento, anticipo, vicios ocultos, fidelidad, fiscal, judicial, etc.)
errorsErrores en extracción (hasError, errorMessage)
tipo_documento = 4

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 documento
0.8Inferido con alta confianza
0.5Incierto/coincidencia parcial
0.0No encontrado en el documento

Texto Extraído

El campo texto_extraido contiene el texto completo del documento como texto plano.

Límites

Tamaño máximo de archivo100MB
Páginas máximas por documento100 páginas
Timeout de webhook30 segundos
Retención de webhook_url30 días

Ejemplos de Integración

Cliente Python

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)

Python (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']}")

    # Responde 2xx para confirmar la entrega
    return jsonify({"status": "received"}), 200

if __name__ == '__main__':
    app.run(port=5001)