2026-10-28 (9)
- Configurar SIAT v3 valida el ambiente.
PUT /api/v1/admin/onboarding/companies/{id}/siat-versiony la toolconfigurarVersionSiatconv3responden422 SIAT_V3_NO_DISPONIBLEal momento de configurar si el ambiente no habla v3 (antes la company quedaba en v3 y fallaba al emitir).verificationUrlahora cae a la consulta oficial del SIN cuando la factura no guardó su QR. Sin Requiere accion.
2026-10-28 (8)
- Nuevo
POST /api/v1/invoices/previewy tool MCPprevisualizarFactura: el mismo body que emitir, pero sin emitir (no numera, no guarda, no toca el SIN). Devuelve montos v2 o v3 según tu company (neto, IVA, monto a pagar, diferencia contra el precio final pedido), el XML que se mandaría y validaciones contra el XSD oficial del SIN y las fórmulas. Ver Previsualizar factura. Sin Requiere accion.
2026-10-28 (7)
- SIAT v3 para todos los sectores en sandbox, sin cambiar tus precios. Si tu company pasa a v3,
priceUnitsigue siendo el precio final que cobras (priceBasis=GROSS, default): cucu deriva el neto y el IVA con el redondeo del SIN y arma el XML como pide la norma. La respuesta (REST, MCP y webhooks) agregasiatVersion,priceBasis,amountNet,amountIva,amountToPay,amountRequestedyamountDifference: cuando un precio final no se puede representar en v3 (ej. Bs 100,00 → 99,99) la diferencia viene explícita, nunca se cobra distinto en silencio. Quien prefiera mandar netos usapriceBasis=NET(por company o por request). Campos nuevos opcionales para v3:incotermScope(3, 20),contractNumber(20, 21),productDescription,locality,originDepartment,originMunicipality(21),beneficiaryComplement(13). El PDF/ticket muestra TOTAL PRECIO NETO e IVA (13 %) en v3. Producción no cambia (RND 102100000011 vigente).
2026-10-28 (6)
- SIAT versión 3 (IVA transparente) en sandbox, por company. El SIN publicó el Anexo Técnico Ley 1733 (RND 102600000034) para
pruebas en el piloto; en producción sigue vigente la RND 102100000011 (v2) y nada cambia. En sandbox, soporte puede pasar
una company a v3 (tool admin
configurarVersionSiatoPUT /api/v1/admin/onboarding/companies/{id}/siat-version), con lo que el XML llevasubTotalNeto,totalPrecioNeto,ivaymontoaPagar. Cómo se interpretapriceUnity qué sectores cubre: ver la entrada (7), que reemplaza a esta. Códigos nuevos en errores:SIAT_V3_NO_DISPONIBLE,SECTOR_NOT_SUPPORTED_V3. Sin Requiere accion hasta que el SIN fije la fecha de producción; lo anunciaremos aquí.
2026-10-28 (5)
- Entrega por WhatsApp y Telegram, decidida por cada empresa. Apagada por defecto. Se activa por el canal de soporte (tool admin
configurarEntregaChatoPUT /api/v1/admin/onboarding/tenants/{code}/entrega-chat), eligiendo canales (clientPhone→ WhatsApp,clientTelegramUserId→ Telegram) y remitente: el número/bot de cucu o el propio de la empresa. Mientras no se active, enviarclientPhoneno genera ningún mensaje. /f/{cuf}se elimina (404): cucu no tiene página de facturas.verificationUrlypublicPageUrltraen la consulta oficial del SIN (la URL del QR). Requiere accion si guardabas links/f/. Vigente en sandbox cuando el despliegue dedevtermine; en producción, con la fecha de cierre de los links públicos.GET /api/v1/public/invoice/{cuf}sin datos del comprador: ya no traeclientNameniclientDocument(el CUF es derivable y la ruta no pide credencial). Requiere accion si los leías de ahí: usaGET /api/v1/invoices/cuf/{cuf}con tu API Key. Sandbox ahora; producción con el próximo despliegue.- Correo al comprador: el botón “Verificar en Impuestos” lleva a la consulta del SIN (
verificationUrl); si la factura no tiene QR, no hay botón. - Sandbox: los links públicos
/api/v1/public/invoice/{cuf}/*responden410 PUBLIC_DOCUMENTS_GONE. Prueba ahí la migración adocuments.
2026-10-28 (4)
Documentos privados (fase 1)
Requiere accion: migrar depdfUrl / links publicos a documents antes de la fecha que se anunciara. MCP descargarDocumento devuelve download_url.
- Nuevos
GET /api/v1/invoices/{id}/documents/{tipo}yGET /api/v1/invoices/cuf/{cuf}/documents/{tipo}(a4,ticket,ticketsiat,chititicket,xml,zip), con API Key. Ver Descargar documentos. - Nuevo
GET|HEAD /api/v1/documents/t/{token}: link temporal (300 s, 3 usos por defecto) para que agentes y apps descarguen el archivo. InvoiceResponse(REST y MCP) agregadocumentsyverificationUrl.pdfUrl,ticketUrl,xmlUrlypublicPageUrlquedan deprecados y se eliminaran al cierre de los links publicos. Los webhooksinvoice.*agregan el bloquedocuments;pdf_urlno cambia por ahora.- MCP
descargarDocumentodevuelvedownload_url,expires_atymax_usesen lugar decontentBase64/sizeBytes, y suma los formatosticketsiat,chititicketyzip. - Links publicos: sin cambios por ahora, salvo
Cache-Control: public, no-cache+ETagtambien en el XML (antes un año) y409en facturas sin documento. Al cerrarse responderan410 PUBLIC_DOCUMENTS_GONEy/f/{cuf}quedara solo para verificacion. Ver Acceso publico. - Codigos nuevos en errores:
DOCUMENT_NOT_AVAILABLE,DOCUMENT_LINK_GONE,PUBLIC_DOCUMENTS_GONE.
2026-10-28 (3)
- Se eliminaron
POST /api/v1/ai/normativas/loadyPOST /api/v1/ai/normativas/reload. No estaban documentados y cualquier API Key podía dispararlos; la carga de normativa pasa a ser una operación de soporte (indexarNormativa, admin).GET /api/v1/ai/normativas/searchy/statussiguen igual.
2026-10-28
Segunda entrega del dia: endurecimiento de seguridad en MCP, webhooks, sincronizacion de catalogos y logo del PDF.MCP: todas las herramientas exigen X-API-Key, utilidades incluidas
Requiere accion si algun cliente MCP llamaba a buscarNormativa, verificarFormatoNit,
consultarDatosNit, erroresComunesSiat, buscarContingencias o calcularMontoLiteral sin llave:
ahora se autentican como el resto de las 49 herramientas y, sin X-API-Key (o con una invalida), el
resultado de la herramienta es Error: API Key requerido. Envie el header X-API-Key con su clave (sk_live_xxx o sk_test_xxx).
Cada llamada cuenta ademas para el limite de requests por minuto de la llave, el mismo que en REST.
buscarContingencias devuelve solo las contingencias del tenant autenticado. Ver
Utilidades SIAT y Autenticacion MCP.
Webhooks: politica de destinos en cada entrega, sin credenciales en la URL, lastError generico
Requiere accion si la URL de algun endpoint lleva credenciales embebidas
(https://usuario:clave@host/...): al registrar o actualizar se rechaza con 400
La URL del webhook no admite credenciales embebidas. Pasa la autenticacion de tu receptor por la firma
webhook-signature o por un token en el path/query, y actualiza la URL con PUT /api/v1/webhooks/endpoints/{id}.
- La URL se valida con una unica politica al registrar/actualizar y en cada entrega: se resuelve el
host, se valida cada IP y la conexion va a la IP validada. Un host que pasa a resolver a una direccion
interna deja de recibir entregas (
lastError = "Destino del webhook no permitido"). - Rangos bloqueados ampliados: ademas de loopback y privadas, CGNAT (
100.64.0.0/10), link-local y metadata (169.254.0.0/16),0.0.0.0/8, multicast, ULA (fc00::/7) e IPv4 embebida en IPv6 (::ffff:, NAT64, 6to4) y Teredo. Lista completa en Webhooks → Seguridad. lastErrorde una entrega ya no trae el detalle de la excepcion: toda falla de red esNo se pudo conectar con el endpoint o no respondió a tiempo; un host que no resuelve o que apunta a una IP bloqueada esDestino del webhook no permitido; una respuesta no2xxesHTTP <codigo>. Si tu integracion parseabalastErrorpara distinguir timeout de conexion rechazada, ya no es posible.- Las entregas no siguen redirecciones (
3xx=HTTP 3xx, fallo) y no leen el cuerpo de tu respuesta.
Sincronizacion de catalogos: POS de otro tenant responde 404
Requiere accion si tu integracion esperaba 403. En POST /api/v1/siat/sync/all y
POST /api/v1/siat/sync/{catalog}, un posId de otro tenant responde 404 POS_NOT_FOUND
(Punto de venta no encontrado), igual que uno inexistente. Antes era 403 FORBIDDEN. Ver
Catalogos.
Logo del PDF: solo el subido por storage
El PDF embebe unicamente el logo guardado porPOST /api/v1/storage/brand/logo (bytes de la empresa o el
objeto bajo brands/{tenantId}/). Nunca se descarga desde una URL: si tu empresa tenia asociada una URL
externa como logo, el PDF sale sin logo hasta que subas el archivo. Ver Storage.
2026-10-28
Emision mas rapida: la respuesta sale apenas el SIN acepta
POST /api/v1/invoices responde en cuanto el SIAT valida la factura (o queda en contingencia).
El PDF (A4 y ticket), la subida a storage, el email al cliente y la notificacion por chat pasan a
entregarse despues, por una cola propia con reintentos. Antes la respuesta esperaba a que todo
eso terminara (varios segundos).
pdfUrl,ticketUrlyxmlUrlsiguen siendo validas desde la respuesta. Si descargas el PDF antes de que la entrega lo haya guardado, se genera en el momento: la primera descarga tarda mas, nunca404. Si otro proceso ya lo esta generando:503DOCUMENT_IN_PREPARATION+Retry-After.- El webhook
invoice.emittedpuede llegar antes que el email al cliente. - Los PDF publicos ya no se cachean un ano:
Cache-Control: public, no-cache+ETagpor version (la misma URL sirve la vigente y la anulada). El XML sigue inmutable. - La reversion de una anulacion reenvia la factura vigente por correo, con asunto
[ANULACIÓN REVERTIDA] ....
201 (o el webhook) el cliente ya tenia el
correo, o que el PDF estaba listo al instante, ajustala. Ver Crear factura.
idempotencyKey en la factura; clave de una factura anulada → 422
- La factura devuelve
data.idempotencyKey(laIdempotency-Keycon la que se emitio,nullsi no se envio) en la emision y enGET /invoices/{id},/cuf/{cuf}y/by-idempotency-key/{key}. - Requiere accion. Reusar la
Idempotency-Keyde una factura anulada responde422conerror.code = IDEMPOTENCY_KEY_CANCELLED: no se devuelve la factura anulada como replay ni se emite otra con esa clave. Para facturar de nuevo, usa una clave nueva.
429 por credenciales invalidas repetidas desde una IP
Requiere accion si tu integracion rota llaves o reintenta un 401 en bucle. Mas de 20
credenciales invalidas por minuto desde una misma IP (API Keys en rutas protegidas, credenciales
admin, API Keys en /mcp) → esa IP recibe 429 con Retry-After presente la llave que presente,
hasta la proxima ventana. El trafico con una llave valida no lo activa, y una request sin credencial
no cuenta. Detalle en Autenticacion.
Reenvio de factura por correo: destino validado y cupo por hora
Requiere accion si reenvias correos de forma automatica.POST /api/v1/invoices/{id}/resend-email:
?email=tiene que ser una sola direccion valida; si no,400.- Cupo de 5 reenvios por factura por hora y 60 por tenant por hora. Superado cualquiera:
429RATE_LIMITED+Retry-After.
Paginacion: tope de 100 por pagina
Requiere accion si pediassize mayor a 100. En GET /invoices y GET /invoices/search,
size > 100 no es error: se sirven 100 y data.size informa el tamano efectivo. size <= 0 → 20;
page < 0 → 0. En MCP, listarFacturas sirve como maximo 50 (antes la documentacion REST decia
“max 50”: el tope REST es 100).
Los 500 devuelven una referencia, no el mensaje interno
error.code = INTERNAL_ERROR, message = "Error interno del servidor" y
error.details = "ref=<uuid>". El detalle real queda solo en los logs de cucu bajo esa referencia:
mandala a soporte. Los 4xx y los errores de dominio conservan su mensaje en message.
Ademas, la pagina de Errores se corrigio para reflejar el sobre real: el objeto error
tiene code y, solo en INTERNAL_ERROR, details; no trae field, siatCode ni
siatDescription. El texto legible siempre va en message.
Recursos de otro tenant responden 404
Requiere accion si tu integracion esperaba 400 para “POS no encontrado”. En /api/v1/events/*
y /api/v1/massive/*, un punto de venta, evento o lote inexistente o de otro tenant responde
404 NOT_FOUND con el mismo mensaje. Antes era 400. Lo mismo aplica a la empresa en la subida
de logo.
Logo de empresa: PNG/JPEG/WebP verificados por contenido, 2 MiB
POST /api/v1/storage/brand/logo: el formato se detecta por los bytes del archivo (PNG, JPEG o
WebP), no por el Content-Type; el body va como application/octet-stream. Limite 2 MiB. Errores
nuevos: 400 LOGO_INVALIDO, 413 LOGO_DEMASIADO_GRANDE, 404 si la empresa no es tuya. La
clave en storage es brands/{tenantId}/logo.{png|jpg|webp}.
Cabeceras de seguridad en las respuestas
Todas las respuestas traenX-Content-Type-Options: nosniff, Referrer-Policy: no-referrer y
Strict-Transport-Security. Las respuestas JSON traen ademas X-Frame-Options: DENY y una CSP
restrictiva; los documentos publicos y /f/{cuf} quedan fuera de esas dos para poder embeberse.
No requiere accion salvo que embebieras respuestas JSON de la API en un iframe.