API de UPO de KSeF: consulta de estado y pruebas que perduran
Crea un flujo fiable para la API de UPO de KSeF: consulta el estado, gestiona fallos terminales, verifica el XML y archiva pruebas de la aceptación.
Ernest Bursa
Para recuperar una UPO de KSeF con seguridad, conserva la referencia de la factura que devuelve la llamada de envío, consulta su estado hasta que alcance un estado terminal y acepta únicamente el estado 200 acompañado de un número KSeF. Después, descarga el XML de la UPO, verifica el hash de la respuesta, el esquema y la firma XAdES, y archiva los bytes exactos. Una respuesta de envío satisfactoria o una URL de la UPO que caduca no prueban que KSeF haya aceptado la factura.
¿Qué prueba que KSeF ha aceptado una factura?
La aceptación exige el resultado asíncrono completo, no un envío HTTP satisfactorio. La llamada de envío devuelve un referenceNumber de la factura e inicia la verificación. No asigna el número KSeF definitivo ni demuestra que el documento haya superado las comprobaciones de KSeF.
Esta diferencia es la base de una integración fiable. Tu aplicación puede recibir una respuesta correcta del endpoint de envío mientras la factura todavía espera la validación. Si en ese momento la marcas como aceptada, tu estado local se adelantará al sistema oficial. Podrías mostrar al cliente un resultado satisfactorio que aún no se ha producido, iniciar antes de tiempo procesos contables posteriores o perder los identificadores necesarios para rastrear un rechazo.
La guía oficial sobre sesiones interactivas explica que la verificación posterior al envío es asíncrona. Guarda de inmediato la referencia de factura devuelta junto con tu factura local y la referencia de sesión. Estos tres identificadores cumplen funciones distintas:
- El ID de la factura local vincula el flujo con tu propio registro empresarial.
- La referencia de sesión identifica la sesión de KSeF empleada para el transporte.
- La referencia de factura identifica este envío mientras KSeF lo procesa.
- El número KSeF solo llega después de la aceptación y pasa a formar parte de las pruebas.
Para obtener un resultado positivo, espera al estado de factura 200, confirma que la respuesta contiene el número KSeF y recupera la UPO. La segunda parte del manual de KSeF 2.0 del Ministerio explica que la aceptación asigna un número KSeF y ofrece la UPO como documento XML independiente.
Así se obtiene un modelo de estados claro: enviada, en proceso, aceptada o fallida. No agrupes el envío y la aceptación en un único estado. La respuesta HTTP demuestra el transporte; el estado 200, el número KSeF y una UPO verificada demuestran el resultado definitivo.
¿Qué endpoint de estado de KSeF debes consultar?
Consulta el estado de la factura individual cuando necesites conocer su resultado. Usa GET /sessions/{referenceNumber}/invoices/{invoiceReferenceNumber} con la referencia de sesión y la referencia de factura guardadas al enviar el documento.
Según la especificación OpenAPI oficial, la respuesta puede incluir el estado de la factura en KSeF, el número legible de la factura local, el número KSeF, el hash de la factura, la fecha de adquisición, la fecha de facturación, la fecha de almacenamiento permanente, el modo de facturación y una URL de descarga de la UPO con su fecha de caducidad. Guarda los campos útiles a medida que aparezcan, sin esperar a que termine toda la sesión.
El endpoint de sesión, GET /sessions/{referenceNumber}, resuelve otro problema. Informa del estado de la sesión y de recuentos agregados como invoiceCount, successfulInvoiceCount y failedInvoiceCount. Para una sesión cerrada, también puede devolver referencias y URLs de descarga de páginas de UPO agregadas.
Esos totales sirven para la conciliación. Permiten comprobar si el número de resultados individuales que has registrado coincide con KSeF. No indican qué número KSeF recibió cada factura local. Además, una sesión puede contener facturas aceptadas y fallidas, por lo que un resultado a nivel de sesión no sustituye al registro de cada factura.
Combina ambas perspectivas:
- Consulta el estado de cada factura para actualizar el que muestras en tu producto o ERP.
- Consulta el estado de la sesión para conciliar los totales y recuperar las páginas de UPO agregadas cuando corresponda.
- Investiga cualquier diferencia entre los recuentos de la sesión y los resultados de factura almacenados.
La guía oficial sobre el estado de las sesiones y la UPO documenta ambos niveles. Mantenerlos separados evita un error de identidad frecuente: tratar la referencia de sesión, la referencia de factura y el número KSeF como si fueran intercambiables.
¿Qué códigos de estado de factura son terminales?
Un proceso de consulta debe detenerse ante todos los estados terminales documentados, no solo cuando obtiene un resultado satisfactorio. Los códigos 100 y 150 siguen en curso. El código 200 indica éxito. Los resultados 4xx y 5xx documentados a continuación exigen gestionar el fallo o investigarlo.
| Código | Significado | Clasificación en producción |
|---|---|---|
100 |
Aceptada para continuar el procesamiento | No terminal |
150 |
En proceso | No terminal |
200 |
Éxito | Éxito terminal |
405 |
Cancelada por un error de sesión | Fallo terminal |
410 |
Ámbito de permisos no válido | Fallo terminal |
415 |
No se puede enviar una factura con archivo adjunto | Fallo terminal |
430 |
Error al verificar el archivo de la factura | Fallo terminal |
435 |
Error al descifrar el archivo | Fallo terminal |
440 |
Factura duplicada | Fallo terminal; inspecciona las extensiones estructuradas |
450 |
Error de validación semántica de la factura | Fallo terminal |
500 |
Error desconocido | Fallo terminal; investigación manual |
550 |
Operación cancelada por el sistema | Investiga y, si corresponde, reintenta en el nivel de la operación |
Estos significados proceden de SessionInvoiceStatusResponse en el contrato OpenAPI actual. Guarda el código numérico, la descripción, los detalles y las extensiones estructuradas que recibas. El texto legible ayuda al equipo de operaciones; el código proporciona a la lógica de la aplicación un punto de decisión estable.
Presta especial atención al estado de duplicado 440. Puede incluir información estructurada sobre la sesión original y el número KSeF. Es un dato que debes investigar, no un permiso para dar por bueno el nuevo intento sin más. Vincúlalo al original solo después de que tus propias reglas de identidad y hash de factura confirmen que ambos registros representan el mismo documento.
Tu analizador también debe tolerar campos desconocidos. El registro de cambios de la API indica que pueden aparecer propiedades adicionales sin que se consideren un cambio incompatible. Los códigos de estado desconocidos deben trasladar la factura a una revisión manual. Nunca deben interpretarse como aceptación por defecto.
¿Cómo debe funcionar la consulta de estado en producción?
En producción, la consulta de estado debe poder reanudarse tras una interrupción, estar acotada y respetar las cuotas. Guarda cada intento, usa backoff exponencial con jitter, respeta Retry-After y deriva a conciliación las facturas que permanezcan en proceso durante un tiempo inusualmente largo, en lugar de consultarlas indefinidamente.
La API publica límites, no un intervalo de consulta obligatorio. La guía oficial sobre límites de la API documenta actualmente 30 solicitudes por segundo, 120 por minuto y 1 200 por hora para el endpoint de estado de una sola factura. Las demás rutas /sessions/*, incluidos los endpoints de estado de sesión y UPO, permiten 10 por segundo, 120 por minuto y 1 200 por hora. Una respuesta 429 incluye Retry-After.
Esta combinación de límites importa. Un bucle que consulta cada segundo puede respetar el límite por segundo durante una prueba pequeña y, aun así, agotar el presupuesto por hora en producción. Un grupo de workers también puede provocar ráfagas sincronizadas tras un despliegue o una interrupción. El jitter distribuye esas solicitudes, mientras que un next_attempt_at persistido permite reanudar el mismo calendario después de un reinicio.
submit invoice
persist local_id, session_reference, invoice_reference, submitted_hash
repeat with bounded exponential backoff and jitter:
response = get invoice status
persist code, details, extensions, checked_at
if response is 429:
schedule next attempt from Retry-After
else if code is 100 or 150:
schedule next attempt
else if code is 200 and ksef_number is present:
persist ksef_number and status timestamps
retrieve, verify, and archive UPO
finish as accepted
else if code is documented terminal failure:
finish as failed and route to the matching repair path
else:
stop automatic acceptance and request manual investigation
if processing exceeds the operational deadline:
move record to reconciliation queue
El plazo operativo es tu salvaguarda, no un estado inventado de KSeF. Debe impedir que un worker concreto reintente la operación indefinidamente y conservar el registro para comprobaciones posteriores. Guarda, como mínimo, la hora del último intento, el número de intentos, los detalles de la última respuesta y el siguiente intento programado. Basta con esos datos para que la consulta resista caídas del proceso.
¿Cómo se recuperan las UPO de factura y de sesión?
Recupera la UPO de una factura después de que esa factura alcance el estado 200; recupera las páginas de UPO agregadas solo cuando se cumplan las condiciones de la sesión. La UPO de una factura puede existir mientras una sesión interactiva siga abierta.
KSeF ofrece tres rutas autenticadas en el contrato OpenAPI actual:
GET /sessions/{sessionReferenceNumber}/invoices/{invoiceReferenceNumber}/upoGET /sessions/{sessionReferenceNumber}/invoices/ksef/{ksefNumber}/upo-
GET /sessions/{sessionReferenceNumber}/upo/{upoReferenceNumber}para una página de UPO agregada
La respuesta de estado también puede proporcionar una upoDownloadUrl o downloadUrl firmada. Descarga el recurso de esa URL de almacenamiento con una solicitud HTTP GET normal y no adjuntes el token de acceso de KSeF. Las descripciones de OpenAPI indican que estas descargas mediante URL firmada no cuentan para los límites de la API y caducan en el momento indicado en la respuesta.
Esta distinción es importante. Las rutas de la API exigen uno de los ámbitos de permisos enumerados en el contrato actual, entre ellos InvoiceWrite, Introspection, PefInvoiceWrite o EnforcementOperations. Las indicaciones antiguas que presentan la recuperación desde la API como no autenticada no reflejan el contrato que hoy debes implementar. La ruta de la API de KSeF exige autenticación; la URL de almacenamiento firmada se descarga sin tu token de acceso.
La UPO de una factura está disponible cuando esa factura se acepta y recibe un número KSeF. La UPO agregada pasa a estar disponible después de cerrar la sesión, procesar todos los documentos y confirmar que al menos uno tiene tanto un número KSeF como almacenamiento permanente. Por eso, cerrar una sesión interactiva no debe ser un requisito previo para recuperar una UPO de factura que ya esté disponible.
¿Cómo se verifica una UPO antes de archivarla?
Archiva la UPO solo después de verificar los bytes exactos de la respuesta frente al hash de transporte, el esquema XML, la firma y tu registro del envío. Analizar el XML correctamente es útil, pero no constituye una comprobación completa de integridad o identidad.
Toda respuesta satisfactoria de descarga de una factura o UPO expone x-ms-meta-hash, un hash SHA-256 codificado en Base64 del documento devuelto. Lee el cuerpo como bytes, calcula SHA-256 sobre esos bytes sin alterar, codifica el resultado en Base64 y compáralo con la cabecera antes de transformar o normalizar el XML.
Después, valida el XML con el XSD oficial de UPO v4-3. UPO v4-3 es la versión predeterminada desde el 22-12-2025 y utiliza un único esquema para las UPO de factura y de sesión. Incluye TrybWysylki, que distingue los modos de envío Online y Offline. El registro de cambios de la API recoge el cambio de versión y el comportamiento del hash.
A continuación, valida la firma XAdES y su cadena de confianza con el material de confianza adecuado del Ministerio. Por último, compara los campos de negocio del documento firmado con tu registro de envío: referencia de sesión, hash de factura, NIP del vendedor, número de factura local, número KSeF, fecha de emisión, marcas temporales de envío y adquisición, y modo de envío.
Realiza estas comprobaciones por separado y conserva el resultado de cada una. Un hash de respuesta correcto demuestra que has guardado los bytes entregados en esa respuesta. La validación del esquema demuestra la conformidad estructural. La validación de la firma cubre la autenticidad y la integridad conforme al modelo de confianza de la firma. La comparación de los campos de negocio demuestra que el documento pertenece a la factura que pretendías procesar.
¿Qué debe contener tu registro de pruebas de KSeF?
Un registro duradero de KSeF debe conservar los identificadores, el historial de estados, los bytes exactos de la UPO y los resultados de verificación. Si solo guardas el número KSeF, no podrás reproducir cómo llegó tu sistema a su conclusión.
| Campo de prueba | Por qué conservarlo |
|---|---|
| Clave primaria y número de la factura local | Vincula las pruebas de KSeF con tu registro contable |
| Hash exacto del XML FA(3) enviado | Identifica el documento enviado y permite comprobar duplicados |
| Números de referencia de sesión y factura | Permiten consultar el estado, recuperar la UPO e investigar incidencias |
| Número KSeF | Registra el identificador asignado tras la aceptación |
| Último código de estado, descripción, detalles y extensiones | Conserva el resultado oficial del procesamiento y el contexto estructurado del error |
| Fechas de facturación, adquisición y almacenamiento permanente | Mantiene separadas marcas temporales distintas en lugar de deducir el estado a partir de su orden |
| Bytes exactos del XML de la UPO | Conserva las pruebas con independencia de la infraestructura de entrega |
SHA-256 calculado y x-ms-meta-hash
|
Registra la comparación de integridad de la respuesta |
| Versión del esquema de la UPO y resultado de validación | Muestra qué contrato estructural se comprobó |
| Firma XAdES y resultado de la cadena de confianza | Registra la comprobación de autenticidad |
| Marcas temporales de recuperación y verificación | Muestran cuándo se recopilaron y comprobaron las pruebas |
| Historial de reintentos, reparaciones, correlación y trazas | Permite reproducir los fallos y diagnosticarlos en producción |
Conserva las tres marcas temporales de KSeF como campos separados. invoicingDate, acquisitionDate y permanentStorageDate describen sucesos distintos. No conviertas su orden aparente en un sustituto de la máquina de estados. El código de estado y los identificadores guardados siguen siendo la referencia para tomar decisiones en el flujo.
Conserva también los bytes sin procesar, aunque extraigas campos útiles para las búsquedas. Una clave de almacenamiento de objetos junto con un hash de contenido puede funcionar bien, siempre que la retención y los controles de acceso respondan a tus requisitos probatorios. La URL que caduca no sustituye al objeto. Es tan solo una vía para obtenerlo.
¿Cómo se recupera el flujo tras fallos y enlaces caducados?
La recuperación parte de los identificadores persistentes y del estado, no de una URL firmada almacenada en caché. Si una URL caduca, vuelve a consultar KSeF mediante el flujo autenticado y obtén una ruta de recuperación vigente.
Ante problemas de transporte o reinicios del proceso, reanuda el trabajo desde la referencia de factura guardada y el estado de la última consulta. Para un 429, respeta Retry-After al pie de la letra. Para los estados 100 y 150, continúa con el calendario acotado. Ante un fallo terminal documentado, deja de consultar y crea una vía de reparación acorde con el error, en lugar de reenviar la factura sin más.
El estado 440 exige un proceso de conciliación específico. Inspecciona sus extensiones estructuradas, localiza el envío original y compara la identidad del registro local con el hash inmutable de la factura. Solo entonces podrás decidir si el documento original aceptado constituye el resultado válido para tu factura local. Una respuesta de duplicado sigue siendo un fallo del intento realizado.
Utiliza el agregado de la sesión como segunda línea de defensa. Compara invoiceCount, successfulInvoiceCount y failedInvoiceCount con tus registros de cada factura. Una discrepancia puede revelar una tarea perdida, un resultado de callback que no se guardó o una factura enviada a revisión manual. La guía sobre sesiones y UPO contiene los campos oficiales del nivel de sesión y las reglas de disponibilidad.
A fecha de 28-08-2026, KSeF API 2.6.1 es la versión más reciente desplegada en PRD. La versión 2.7.1 llegó a TEST el 26-08-2026; su despliegue en DEMO está previsto para el 15-09-2026 y en PRD, para el 23-09-2026. Los cambios documentados no alteran este flujo de estados y UPO, pero la documentación de producción no debe presentar la versión 2.7.1 como la versión de producción antes de ese despliegue. Vuelve a consultar el registro de cambios oficial cuando implementes o revises la integración.
Cómo cierra KSeF Kit el ciclo probatorio
KSeF Kit aplica el mismo flujo, centrado en las pruebas, a las facturas de Stripe. Convierte las facturas finalizadas de Stripe a FA(3), las envía, espera su aceptación, almacena la UPO y escribe el número KSeF en los metadatos de Stripe.
Esta implementación resulta útil porque mantiene visible el punto en el que comienza el procesamiento asíncrono. Que la factura se finalice en Stripe no significa que KSeF la haya aceptado. KSeF Kit espera el resultado oficial y conserva el documento que lo demuestra. Puedes consultar la documentación del flujo de presentación para conocer la secuencia completa o visitar la página de KSeF Kit para ver la integración compatible con Stripe.
La regla general es la misma tanto si creas la integración como si utilizas un producto: conserva todas las referencias, detente ante cada estado terminal, verifica el documento descargado y archiva pruebas que sigan disponibles cuando caduque la URL. Así, una llamada satisfactoria a la API se convierte en un resultado que más adelante podrás conciliar y acreditar.
Si emites facturas mediante Stripe y prefieres no crear por tu cuenta este flujo de consulta y archivo de pruebas, descubre cómo KSeF Kit las presenta y registra.
Artículos relacionados
¿Listo para contratar de forma más inteligente?
Empieza gratis durante 30 días. Cancela antes de que termine y no pagas nada. Configura tu primer pipeline de contratación en minutos.
Empieza gratis