Activación y emisión eCF
Producción (eCF) se activa sola cuando el cliente completa la certificación:
- El run del set de pruebas termina con su evidencia.
- Registras las cinco acciones del cliente en la DGII (la última, los roles en la OFV, solo es posible cuando la DGII lo habilitó).
- ZarelaFact registra la Aprobación DGII verificada, el caso pasa a
approvedy, con el certificado vigente, la Cuenta fiscal queda en producción.
Recibes el webhook production.state_changed con state: "active". También puedes consultar GET /fiscal-accounts/{id}/production. Mantén la emisión bloqueada en tu UI mientras state no sea active.
La DGII sigue siendo el control fiscal: solo acepta e-CF de contribuyentes autorizados.
La certificación y las pruebas de tus clientes son gratis. Para emitir en eCF tu Partner necesita un plan pagado (sin tramo gratis), con un cupo mensual para todos tus clientes juntos. Sin plan, o con el pago vencido tras los 7 días de gracia, la emisión responde 402 PAYMENT_REQUIRED. Ver Planes y pagos.
Reintentar la activación
Si el caso quedó approved sin certificado vigente (por ejemplo, venció antes de terminar), carga el certificado nuevo y repite la activación:
curl -sS -X POST \
"$BASE_URL/fiscal-accounts/$FISCAL_ACCOUNT_ID/production-activation-requests" \
-H "X-PARTNER-KEY: $PARTNER_KEY" -H 'Content-Type: application/json' \
--data "{\"certificationCaseId\":\"$CASE_ID\"}"
- Con el caso
approvedy el certificado vigente, la respuesta traestate: "active". 409 CERTIFICATE_NOT_ACTIVE: falta un certificado vigente; no queda ninguna solicitud pendiente.409 CERTIFICATION_NOT_APPROVED: el caso todavía no estáapproved.409 PRODUCTION_STATE_CONFLICT: la cuenta ya está activa.- Si ZarelaFact suspendió la Cuenta fiscal (por ejemplo, por un incidente), la solicitud queda en
activation_requestedy la decide ZarelaFact.
Emitir
Tu ERP/POS asigna y conserva el eNCF y envía el JSON fiscal completo, con el emisor incluido, dentro de document. El formato es el mismo de la cuenta directa: ver Formato de documentos.
1. Prevalida (funciona aunque eCF no esté activo): no firma, no envía a DGII, no reserva secuencia ni genera webhooks.
curl -sS -X POST \
"$BASE_URL/fiscal-accounts/$FISCAL_ACCOUNT_ID/production/documents?validate=true" \
-H "X-PARTNER-KEY: $PARTNER_KEY" -H 'Content-Type: application/json' \
--data '{"document":{"ECF":{"...":"JSON DGII/XSD completo"}}}'
2. Emite con el mismo cuerpo, sin validate=true. La respuesta 202 encola el documento: guarda result.documentId, result.encf y correlationId.
Si tu cliente imprime en un punto de venta, agrega la cabecera Prefer: wait=10: la emisión espera hasta 10 segundos a que la DGII responda (TrackID del e-CF, o Aceptado/Aceptado Condicional del resumen RFCE de una factura de consumo menor a RD$250,000) y responde 201 con result.securityCode, result.qrUrl y result.printing. Si la DGII no responde a tiempo, responde el 202 de siempre con Retry-After. Funciona igual que en la cuenta directa: ver Respuesta inmediata para imprimir.
curl -sS -X POST \
"$BASE_URL/fiscal-accounts/$FISCAL_ACCOUNT_ID/production/documents" \
-H "X-PARTNER-KEY: $PARTNER_KEY" -H 'Content-Type: application/json' \
-H 'Prefer: wait=10' \
--data '{"document":{"ECF":{"...":"JSON DGII/XSD completo"}}}'
| Respuesta | Qué hacer |
|---|---|
201 | Solo con Prefer: wait. La DGII respondió: imprime con result.printing y espera el estado final. |
202 | Documento encolado; espera el estado final. |
423 PRODUCTION_NOT_ACTIVE | No emitas; espera production.state_changed con active. |
422 con errors[].field en el RNC emisor | El documento usa un RNC distinto al de la Cuenta fiscal. Corrige el documento. |
402 PAYMENT_REQUIRED | Tu Partner no tiene un plan pagado o el pago está vencido tras los 7 días de gracia (details.reason). Las pruebas y la certificación siguen gratis. El propietario del Partner paga en details.billingUrl; no reintentes. |
429 PLAN_LIMIT_EXCEEDED | Se alcanzó el cupo mensual del plan, sumando todos tus clientes. No reintentes con otro cliente: cambia a un plan mayor desde el portal. |
No necesitas Idempotency-Key para emitir: ZarelaFact deduplica por cuenta, ambiente y eNCF. Ante un timeout reenvía el mismo JSON con el mismo eNCF. Si el eNCF llega con contenido fiscal distinto, se rechaza.
Conciliar el estado
202 significa encolado, no aceptado por la DGII. Para converger al estado fiscal:
| Necesitas | Ruta |
|---|---|
| Estado de varios documentos | POST /fiscal-accounts/{id}/production/documents/status/batch con {"documentIds":["..."]} |
| Estado de uno | GET /fiscal-accounts/{id}/production/documents/{documentId} |
| Aviso de cambios | Webhook document.state_changed |
Usa los webhooks para reaccionar rápido y la consulta por lote para reconciliar periódicamente. Los estados posibles están en Estados del documento.
Ambas consultas devuelven además:
| Campo | Para qué |
|---|---|
printing | Código de seguridad, fecha de firma y URL del QR para imprimir la factura. Aparece segundos después de emitir, cuando la DGII responde (TrackID o respuesta del resumen RFCE); printingStatus dice por qué todavía no. Ver Representación impresa. |
dgiiMessages | Motivos de rechazo u observaciones de la DGII, para mostrárselos a tu usuario. |
receiverDelivery | Si el comprador es receptor electrónico, la entrega del e-CF a su sistema: state (sent, retry_scheduled, failed, uncertain, not_electronic…), attempts, nextAttemptAt y lastError. null si no tuvo entrega. Ver Campos de cada resultado. |
La consulta por lote y el webhook traen también lastError cuando un documento no avanza: por ejemplo DGII_CERTIFICATE_NOT_DELEGATED, si el certificado del cliente no está delegado en la DGII. En ese caso los envíos de esa Cuenta fiscal quedan en pausa y se reintentan cada 30 minutos hasta que el cliente delegue el rol Firmante Autorizado en la Oficina Virtual de la DGII. Muéstrale el hint. Ver Por qué un documento no avanza.
Para un comprador con RNC, el aviso BUYER_RNC_NOT_IN_DGII_REGISTRY o BUYER_RNC_NOT_ACTIVE_IN_DGII en warnings no bloquea la emisión; ver Aviso sobre el RNC del comprador.
Descargar XML y PDF
curl -o factura.pdf -H "X-PARTNER-KEY: $PARTNER_KEY" \
"$BASE_URL/fiscal-accounts/$FISCAL_ACCOUNT_ID/production/documents/$DOCUMENT_ID/pdf"
/pdfdevuelve la representación impresa tamaño carta y/xmlel XML firmado. La respuesta es el archivo, no JSON.- Requiere
documents:read. Antes de la firma responde409 DOCUMENT_NOT_SIGNED.
Anular eNCF no usados
- Prevalida:
POST /fiscal-accounts/{id}/production/annulments/prevalidatecon{"ranges":[{"ecfType":"E31","sequences":[{"desde":"E310000000150","hasta":"E310000000160"}]}]}. - Envía el mismo cuerpo a
POST /fiscal-accounts/{id}/production/annulmentscon la cabeceraIdempotency-Key. Ante un timeout, repite con la misma clave: la DGII no recibe la anulación dos veces.
Las respuestas y errores son los de la anulación de la cuenta directa: 202 si la DGII la acepta, 422 si la rechaza y 502 si el resultado quedó incierto. Un e-CF firmado que nunca salió hacia la DGII se puede anular y queda cancelado al aceptarse la anulación. Anular exige producción activa (423 PRODUCTION_NOT_ACTIVE).
Documentos recibidos y aprobación comercial
Cuando un proveedor envía un e-CF a tu cliente, recibes el webhook document.received con el inboundDocumentId. También puedes listarlos con GET /fiscal-accounts/{id}/production/inbound-documents: pagina por cursor y filtra por grupo (por ejemplo group=por_aprobar), tipo, e-NCF, RNC del proveedor y fecha de recepción, igual que la lista de la cuenta directa. Cada documento por aprobar trae commercialApprovalDeadline, el día 15 del mes siguiente a su emisión; ver Plazo para responder.
Para aceptarlo o rechazarlo comercialmente:
curl -sS -X POST \
"$BASE_URL/fiscal-accounts/$FISCAL_ACCOUNT_ID/production/inbound-documents/$INBOUND_ID/commercial-approval" \
-H "X-PARTNER-KEY: $PARTNER_KEY" -H 'Content-Type: application/json' \
--data '{"decision":"reject","rejectionReason":"Mercancía no recibida"}'
El cuerpo, la respuesta y los errores (422 ACECF_DGII_REJECTED, 503 DIRECTORY_DGII_AUTH_FAILED…) son los de la aprobación comercial de la cuenta directa.
Cuando tu cliente emite a un comprador que es receptor electrónico, ZarelaFact le entrega el e-CF después de que la DGII lo acepta; ver Entrega al comprador.
Consumo del periodo
GET /billing/usage devuelve cuántos e-CF aceptó la DGII en eCF, sumando todas tus Cuentas fiscales, en el periodo de cobro actual de tu plan (periodBasis: subscription; se renueva el mismo día cada mes). Con ?month=YYYY-MM devuelve ese mes calendario de República Dominicana (periodBasis: calendar_month). El periodo actual es lo que consume el cupo de tu plan; es una consulta operativa, no una factura. Ver Planes y pagos.