Certificación como emisor electrónico — estado técnico¶
Qué exige el Proceso de Certificación para ser Emisor Electrónico de la DGII, y qué tenemos. Este documento existe para que cuando el equipo del proyecto pida "lo técnico", la respuesta esté lista y sea comprobable.
El proceso tiene tres etapas: Solicitud (formulario en la OFV + postulación firmada), Set de Pruebas (datos, simulación y comunicación) y Certificación. Los requisitos previos —RNC, clave OFV, alta de NCF, certificado digital del Usuario Administrador e-CF, estar al día— son administrativos y los lleva el equipo del proyecto, no el software.
Las tres URL que hay que declarar¶
El formulario de postulación pide tres direcciones de servicios nuestros, y el paso 12 las vuelve a pedir para el ambiente productivo. Las tres existen:
| Campo del formulario | Ruta | Qué hace |
|---|---|---|
| URL Autenticación | GET /fe/autenticacion/api/semillaPOST /fe/autenticacion/api/validacioncertificado |
Entrega una semilla, la recibe firmada y devuelve un token |
| URL Recepción | POST /fe/recepcion/api/ecf |
Recibe e-CF de terceros y responde el ARECF firmado |
| URL Aprobación | POST /fe/aprobacioncomercial/api/ecf |
Recibe aprobaciones/rechazos comerciales (200 / 400) |
Requisitos del estándar para las tres: SSL, puertos tradicionales, accesibles desde internet y no sensibles a mayúsculas/minúsculas. El host es lo único que cambia entre contribuyentes.
Otros campos del formulario (Tipo de Registro, Tipo de Software, Nombre del Software,
Versión de Software, Datos del Proveedor) son declarativos: los completa el equipo del proyecto.
El servicio de autenticación¶
Es el espejo del que consumimos contra la DGII, con los papeles invertidos:
- El contribuyente pide
GET /fe/autenticacion/api/semilla→ devolvemos unSemillaModelcon un valor único. - Lo firma con su certificado y lo envía a
POST /fe/autenticacion/api/validacioncertificado(multipart, partexml). - Comprobamos, en este orden: estructura contra
semilla.xsd→ firma digital → que la semilla la emitiéramos nosotros, siga viva y no se haya usado → RNC del titular del certificado. - Devolvemos
{ token, expira, expedido }.
Los nombres de recurso son los del estándar del RECEPTOR, no los del servicio de la DGII. La DGII expone
/autenticacion/api/autenticacion/semillayvalidarsemilla; a los contribuyentes se les exige/fe/autenticacion/api/semillayvalidacioncertificado, porque "la única diferencia entre los servicios de los contribuyentes sea la dirección de host" (Descripción Técnica Servicios Emisores Electrónicos, Creación de Servicios). Confundirlos deja el servicio inalcanzable para quien siga la norma.
Detalles que importan:
- Anti-replay. La semilla se registra al emitirse y se consume al usarse (
Cache::pull), con una ventana de 5 minutos. Sin esto, una semilla firmada capturada de una sesión anterior serviría para siempre, y una semilla inventada por el llamante también. - El token no se guarda en claro: se indexa por
sha256, así que quien lea el almacén de caché no obtiene tokens utilizables. Vive una hora (DGII_RECEIVER_TOKEN_TTL). - Una semilla sin firmar la rechaza el propio esquema: en
semilla.xsdelxs:anyfinal —el hueco de la<Signature>— es obligatorio. - El token queda asociado al titular del certificado, no a una company nuestra: quien se autentica es un contribuyente externo.
Por qué el token es opcional en recepción y aprobación¶
DGII_RECEIVER_REQUIRE_TOKEN está en false por defecto, y es una decisión deliberada: en las
pruebas de comunicación (pasos 9 a 11) es la DGII quien nos envía los comprobantes y las
aprobaciones, y exigir un token que no llegue haría fallar el paso. La legitimidad de fondo no
depende del token: la firma digital del documento se verifica siempre, y el RNC comprador tiene
que corresponder a uno de nuestros emisores.
Lo que sí es innegociable: un token presente pero inválido se rechaza con 401. Si el llamante decide identificarse, esa identidad tiene que sostenerse.
El set de pruebas, paso a paso¶
| Paso | Qué pide la DGII | Estado |
|---|---|---|
| 1 | Postulación en XML, firmada | Administrativo |
| 2 | Pruebas de datos e-CF: generar los XML desde un Excel que ellos dan y enviarlos a recepción | Listo — los 10 tipos |
| 3 | Pruebas de datos de aprobaciones/rechazos comerciales desde otro Excel | Listo |
| 4 | Pruebas de simulación: e-CF con datos reales de la operación | Listo |
| 5 | Enviar las representaciones impresas en PDF (máx. 10 MB) | Listo — RI conforme a §18 |
| 6 | Validación de la RI por la DGII | Revisión manual de ellos |
| 7 | Actualizar las URL de prueba | Las tres existen |
| 8 | Descargar el certificado raíz y declararse listo | Listo — falta instalar el fichero |
| 9 | Recepción de e-CF enviados por la DGII → devolver acuses | Listo — ARECF firmado |
| 10-11 | Recepción de aprobaciones comerciales → responder OK / Error | Listo — 200 / 400 |
| 12 | URL de los servicios en producción | Las tres existen |
| 13 | Declaración jurada firmada | Administrativo |
Dos avisos sobre el set de pruebas¶
Un rechazo obliga a reiniciar. La nota al pie del paso 2 es explícita: "en el caso de que un e-CF generado resulte con estado Rechazado, deberá reiniciar la generación del set de datos de prueba". Eso cambia el cálculo: conviene agotar la auditoría del núcleo antes de la certificación, porque un campo mal emitido no cuesta un reintento, cuesta el set completo.
Hay que poder expresar lo que venga en su Excel. El set exige generar los XML "con los mismos
campos y en el mismo orden" del archivo que ellos entregan. Si trae bloques que nuestro JSON
canónico todavía no expresa —los campos de ISC de alcoholes y tabaco (CantidadReferencia,
GradosAlcohol, PrecioUnitarioReferencia, Subcantidad) son los candidatos conocidos— hay que
implementarlos antes, no durante.
Riesgos abiertos¶
- Cadena de confianza: implementada, pendiente de instalar el fichero. Ver
cadena-de-confianza.md. El código ya comprueba vigencia y cadena; lo que
falta es un fichero, no desarrollo: descargar el raíz del portal (paso 8), reunir las intermedias de
las CAs acreditadas por INDOTEL, apuntar
DGII_TRUST_AUTHORITIESy activarDGII_TRUST_REQUIRE_CHAINantes de producción. - Sesión ante la DGII. Ya no es un riesgo: las llamadas autenticadas renuevan la sesión y
reintentan una vez ante un 401 (
DgiiClient::authenticated()), así que una sesión caída a mitad de la operación no cuesta un documento sin transmitir. - Nada probado en vivo. Todo lo anterior está verificado contra los esquemas oficiales y con
certificados autofirmados. El
.p12real es lo que convierte esto en una afirmación comprobada.
Antes de dar el paso 8 por bueno¶
El paso 8 es "descargar el certificado raíz y declararse listo", y es fácil de dar por hecho: se baja
un fichero y se sigue. Pero un raíz descargado y no instalado —o instalado donde el proceso de PHP no
lo lee— no da error en ningún sitio: simplemente no se comprueba nada. Y al contrario, activar
DGII_TRUST_REQUIRE_CHAIN con las raíces incompletas rechaza comprobantes legítimos, uno por uno.
Por eso hay un comando de diagnóstico:
Lista las raíces que el proceso está leyendo de verdad (con su vencimiento), si hay intermedias, y comprueba que nuestros propios certificados de firma encadenen hasta alguna de ellas. Si nuestro certificado no encadena, el de un tercero tampoco lo hará.