Cómo extraer datos de facturas PDF para COMEX en LATAM
Extraer datos de facturas PDF para COMEX en LATAM no es como procesar una factura local: cambian formatos, monedas, identificadores fiscales y los line items vienen por cientos. Cómo resolverlo con un schema único y un par de líneas de código.
Extraer datos de facturas PDF en una operación de comercio exterior en LATAM se ve, hoy, así: alguien sentado frente al PDF tipeando. Una factura internacional con 80 line items llega por mail, alguien la abre, y empieza a transcribir SKU por SKU al ERP. Si tienes suerte el PDF es nativo; si no, es un escaneo de un escaneo. Esa persona puede estar en una agencia de aduana en Valparaíso o en el área de COMEX de una importadora en Ciudad de México — el dolor es el mismo.
Este post es para el dev que está construyendo el software que va a reemplazar ese trabajo manual. Vamos a ver por qué hacerlo bien para COMEX es harto más difícil que procesar una factura local, por qué los enfoques clásicos (OCR plano, regex, templates) se quiebran apenas el segundo exportador entrega un PDF distinto, y cómo se resuelve con un schema bien diseñado y una API que entiende el documento en vez de mirarlo letra por letra.
Por qué extraer datos de facturas PDF en COMEX es otro problema
La factura internacional —el documento que lista los productos, cantidades, precios unitarios y totales de la operación— es la pieza central del expediente COMEX. Alrededor giran el packing list, el bill of lading, los certificados de origen, y los documentos aduaneros país-específicos: DUS en Chile, pedimento en México, DEX en Colombia, DAM en Perú. Pero la factura es la fuente de verdad sobre qué se está moviendo y por cuánto.
El problema es que esa factura no tiene un formato estándar. Una factura tributaria chilena la dicta el SII y todas se ven parecidas. Una factura comercial internacional la emite cualquier exportador en cualquier país, en su propio template, en el idioma que quiera. Tienes:
- Volumen impredecible. Una factura de un exportador chino con productos electrónicos puede traer 200 líneas, distribuidas en 12 páginas, con descripciones en inglés y subtotales por SKU.
- Variabilidad estructural. El mismo importador trabaja con 30 proveedores distintos, cada uno con su layout. Hoy llega una factura de Alemania con columnas en alemán, mañana una de Vietnam donde el peso neto está en una columna escondida abajo a la derecha.
- Identificadores fiscales heterogéneos. RUT chileno con dígito verificador, RFC mexicano de 12-13 caracteres, RUC en Perú y Paraguay, NIT colombiano, CUIT argentino, VAT europeo. El campo que llamas
tax_iden tu schema tiene que aceptar todo eso sin validación rígida. - Monedas múltiples. USD es el default, pero también aparecen EUR, CNY, JPY, BRL, CLP, MXN. Y hay sutilezas: CLP y JPY no usan decimales, mientras que la mayoría sí.
- Datos COMEX que la factura local no tiene. Códigos arancelarios HS (formato
0000.00.00o0000.00.00.00), país de origen ISO 3166-1, puerto de carga, puerto de descarga, INCOTERMS.
Y al final del proceso, todo eso tiene que entrar perfecto al sistema interno —ERP, TMS, sistema aduanero— porque un dígito mal en un HS code te cambia el arancel.
Cómo se hace hoy: transcripción manual u OCR plano
Hoy hay dos enfoques en producción y ambos duelen.
El primero es transcripción manual. Operadores leyendo el PDF y tipeando al ERP. Esto es caro, lento, y propenso a errores. Una factura densa puede tomar 30-60 minutos de trabajo humano. En agencias de aduana medianas hay equipos completos dedicados a esto. El error humano se mete por todos lados: confundir un 0 con una O en un código arancelario, sumar mal cantidades, copiar una descripción de la línea de arriba.
El segundo es OCR tradicional + regex/templates. Servicios como Tesseract o Textract te entregan el texto del PDF; sobre eso aplicas regex o templates por proveedor. Funciona razonablemente bien si tienes 5 proveedores estables y sus formatos no cambian. Pero apenas tienes 30 proveedores distintos, o uno cambia su template, el sistema se cae. Para hacer extracción de datos con IA real —no solo OCR— necesitas que el modelo entienda qué es cada cosa, no dónde está visualmente. Y herramientas genéricas tipo Textract o Reducto no están entrenadas para los matices de COMEX en LATAM: confunden el RUT del exportador con un número de factura, o pierden líneas cuando la tabla cruza páginas.
Hay otro problema más sutil: muchos PDFs de COMEX son un solo archivo con varias facturas adentro. El proveedor te manda un PDF con tres facturas pegadas. El OCR plano no separa eso. Termina mezclando los totales y rompe la conciliación contra la orden de compra.
Un mejor enfoque: schema fijo + extracción semántica
La forma correcta de extraer datos de documentos con IA para este caso es invertir el problema: en vez de mirar el PDF y tratar de adivinar dónde están los campos, defines el schema que tu sistema necesita y dejas que el modelo encuentre cada campo en el documento, sin importar dónde esté visualmente o en qué idioma.
Esto es lo que hace DocuTray con tipos de documento. Defines —o reutilizas uno público— un JSON schema con los campos que te interesan, y la API recibe el PDF y devuelve los datos estructurados. Para facturas internacionales el schema clave incluye:
{
"facturas": [
{
"nombre_emisor": "string",
"id_emisor": "string",
"nombre_receptor": "string",
"id_receptor": "string",
"fecha_factura": "date",
"numero_factura": "string",
"moneda": "USD | EUR | CLP | MXN | ...",
"total_a_pagar": "number",
"puerto_origen": "string",
"puerto_destino": "string",
"productos": [
{
"linea": "integer",
"codigo": "string",
"descripcion": "string",
"cantidad": "number",
"unidad_medida": "string",
"precio_unitario": "number",
"precio_total": "number",
"peso_neto_kg": "number",
"codigo_aduanero": "string",
"codigo_pais_origen": "string"
}
]
}
]
}
Tres detalles que importan en este schema y que son consecuencia directa de los dolores que listamos arriba:
facturases un array. Si el PDF trae varias facturas pegadas, las recibes separadas. Esto solo lo resuelves bien si el modelo entiende cuándo termina una factura y empieza la siguiente — no es un problema de OCR, es un problema de comprensión semántica.monedaes un enum ISO 4217. En vez de inventar tu propio formato, usas los códigos ISO 4217 — USD, EUR, CLP, MXN, CNY, los 49 que cubren todo lo que vas a ver en LATAM. Tu sistema downstream ya sabe qué hacer con eso.id_emisoreid_receptorson strings libres. No los validas con regex en el schema porque sabes que va a llegar RUT, RFC, RUC, NIT, CUIT, VAT. La validación contra el formato correcto la haces después, cuando ya sabes el país de la operación.
Y tres líneas de Python para procesar una factura:
from docutray import DocuTray
client = DocuTray(api_key=os.environ["DOCUTRAY_API_KEY"])
result = client.convert(
file_path="factura_china_oct_2026.pdf",
document_type="factura_internacional",
)
for factura in result.data["facturas"]:
print(f"{factura['numero_factura']} - {factura['moneda']} {factura['total_a_pagar']}")
for p in factura["productos"]:
print(f" L{p['linea']:03d} HS={p['codigo_aduanero']} {p['descripcion'][:40]} x{p['cantidad']}")
Y el resto del expediente —packing list, bill of lading, certificados de origen, los documentos aduaneros país-específicos— se procesa exactamente igual: mismo SDK, mismo flujo, distinto document_type. Cada uno con su schema, todos llegan a tu sistema como JSON limpio.
Los edge cases que sí importan
Esta es la parte que un tutorial genérico nunca cubre. Si solo has procesado facturas de tu propio país, te van a sorprender.
Identificadores fiscales que rompen tu validador. El RUT chileno normalmente viene con guión y dígito verificador (76.123.456-7), pero los exportadores en zona franca de Iquique a veces lo emiten sin guión o con el DV separado por un espacio. El RFC mexicano puede ser de persona física (13 caracteres) o moral (12). El RUC peruano son 11 dígitos exactos pero el de Paraguay tiene formato distinto. Si en tu DB tienes un campo tax_id con regex de validación, vas a rechazar facturas legítimas. Acepta el string como viene y valida contextualmente cuando ya sabes el país.
Tablas densas que cruzan páginas. Una factura con 200 line items reparte la tabla en 8 páginas. La fila 47 puede tener su descripción cortada porque el header de la página siguiente la interrumpe. Servicios genéricos truncan o duplican filas en este escenario. El test concreto: cuenta cuántas líneas tiene la factura visualmente y compara con cuántas devolvió la API. Si el número no calza, ningún campo es confiable.
Monedas sin decimales. CLP no usa decimales: 1.500.000 es un millón quinientos mil pesos chilenos, no mil quinientos. JPY tampoco. Si tu schema parsea el total como float, vas a tener errores de magnitud según la moneda. La regla del schema debería ser: total_a_pagar siempre como number y la conversión a entero/decimal la haces sabiendo qué moneda es.
HS codes con formato variable. El código arancelario armonizado tiene base de 6 dígitos internacionales (0000.00), pero cada país agrega 2 a 4 dígitos más. Chile usa 8 (8471.30.00), México y Argentina pueden usar 8 a 10. Si tu validador exige 8 exactos vas a rechazar facturas válidas con HS code más corto que el exportador no completó.
Idioma del documento. Una factura emitida en China puede venir en inglés con campos en mandarín simplificado mezclados. Una factura italiana tiene Fattura, Numero, Data. El schema en español funciona porque el modelo mapea semánticamente — entiende que Invoice Number y Numero Fattura son ambos numero_factura. No traduzcas a mano.
Glosa de mercancía libre. El campo descripcion puede ser cualquier cosa: a veces es un código (MFR-7823-X), a veces una frase larga ("Cable HDMI 2.1 8K con conectores chapados en oro 2 metros"), a veces ambos en celdas distintas. El schema deja descripcion como string libre y deja que el dev decida después si quiere intentar normalizarlo.
Probar sin escribir una línea de código
Si quieres validar antes de integrar, en app.docutray.com ya existe un tipo de documento público para facturas internacionales con este mismo schema. Subes un PDF con tus facturas reales —una sola, varias pegadas, escaneadas, lo que sea— y obtienes el JSON estructurado de vuelta. Hay uso mensual gratuito, suficiente para probar con varios proveedores y ver cómo se comporta antes de integrar el SDK.
Cuando quieras llevar esto a producción, el flujo es directo: el mismo document_type que probaste en la app es el que invocas desde el SDK. No hay paso de "configurar el schema en el dashboard" — ya está.
Procesar facturas internacionales para COMEX no es un problema de OCR; es un problema de entender el documento. Una vez que cambias el approach —schema fijo, extracción semántica, validación contextual— lo que tomaba media hora por factura toma segundos, y el dev que construye el sistema deja de ser el cuello de botella del agente de aduana o del área de comercio exterior. ¿Tienes una factura rara que crees que ningún servicio podría procesar bien? Pruébala — esos son justamente los casos donde la diferencia se nota.