{"openapi":"3.1.0","info":{"title":"Firmo API","version":"1.0.0","description":"API de facturación electrónica e-CF (DGII, República Dominicana). Emite, consulta y recibe comprobantes fiscales electrónicos. Autenticación con `Authorization: Bearer sk_…`.","contact":{"name":"Firmo","url":"https://firmo.do"}},"servers":[{"url":"https://api.firmo.do"}],"tags":[{"name":"Cuentas"},{"name":"Usuarios y sesiones","description":"Personas que entran al portal con correo y contraseña"},{"name":"API keys","description":"Solo con sesión del portal"},{"name":"Catálogo","description":"Clientes y productos de la empresa"},{"name":"e-CF emitidos"},{"name":"Importaciones","description":"Facturas en lote desde la plantilla de Excel o un CSV: vista previa validada, emisión y resultados"},{"name":"Recibidos"},{"name":"Empresa"},{"name":"Secuencias"},{"name":"Webhooks"},{"name":"Consultas"},{"name":"Certificación DGII","description":"Los 16 pasos (0–15) del portal CerteCF, guiados y automatizados"},{"name":"WhatsApp","description":"Facturar por WhatsApp con la cuenta de Twilio de cada empresa: configuración, vincular el número del usuario y el webhook de mensajes entrantes"},{"name":"Público","description":"Enlaces firmados que no requieren API key (p. ej. el PDF que se envía por WhatsApp)"},{"name":"Receptor DGII","description":"Servicios que la DGII y otros emisores llaman. Base: /dgii/{rnc}"},{"name":"Sistema"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key de Firmo: `sk_test_…` (sandbox) o `sk_live_…` (producción). El portal usa una sesión `ses_…` (POST /v1/auth/login); con sesión, el header `Firmo-Environment: sandbox` fuerza el sandbox."}},"schemas":{"Salud":{"type":"object","properties":{"estado":{"type":"string","enum":["ok","degradado"]},"baseDatos":{"type":"boolean"},"version":{"type":"string"},"rol":{"type":"string"},"activoSeg":{"type":"number"}},"required":["estado","baseDatos","version","rol","activoSeg"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"codigo":{"type":"string","description":"p. ej. validacion, no_autorizado, secuencia_agotada, certificado_faltante"},"mensaje":{"type":"string"},"detalles":{}},"required":["codigo","mensaje"]}},"required":["error"]},"AdminCrearCuentaInput":{"type":"object","properties":{"razonSocial":{"type":"string","minLength":2,"maxLength":150},"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$","description":"Opcional en sandbox: si no se indica se asigna un RNC ficticio"},"nombreDueno":{"type":"string","minLength":2,"maxLength":100},"correoDueno":{"type":"string","format":"email"},"plan":{"type":"string","enum":["sandbox","emprende","negocio","integrador","volumen"],"default":"sandbox"},"ciclo":{"type":"string","enum":["mensual","anual"],"default":"mensual"},"precioAcordado":{"type":["number","null"],"exclusiveMinimum":0,"maximum":100000000,"description":"Precio mensual en RD$ sin ITBIS; anula el de lista (obligatorio en Volumen)"},"proximoCobro":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["razonSocial","nombreDueno","correoDueno"]},"AdminMotivoInput":{"type":"object","properties":{"motivo":{"type":"string","minLength":3,"maxLength":500}},"required":["motivo"]},"AdminCambiarPlanInput":{"type":"object","properties":{"plan":{"type":"string","enum":["sandbox","emprende","negocio","integrador","volumen"]},"ciclo":{"type":"string","enum":["mensual","anual"]},"precioAcordado":{"type":["number","null"],"exclusiveMinimum":0,"maximum":100000000,"description":"null quita el precio acordado y vuelve al de lista"},"proximoCobro":{"type":["string","null"],"pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"estadoCobro":{"type":"string","enum":["al_dia","vencido","sin_cobro"]},"motivo":{"type":"string","minLength":3,"maxLength":500}},"required":["motivo"]},"AdminPagoInput":{"type":"object","properties":{"monto":{"type":"number","exclusiveMinimum":0,"maximum":100000000,"description":"RD$ SIN ITBIS. Si se omite se usa lo que corresponde al ciclo de la cuenta. El ITBIS (18%) y el total se calculan"},"metodo":{"type":"string","enum":["transferencia","tarjeta","efectivo","otro"]},"fechaPago":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Por defecto, hoy (hora de RD)"},"referencia":{"type":["string","null"],"maxLength":120},"nota":{"type":["string","null"],"maxLength":500},"avanzarCobro":{"type":"boolean","default":true,"description":"Mueve `proximoCobro` un ciclo y deja la cuenta al día"}},"required":["metodo"]},"PlataformaWhatsappInput":{"type":"object","properties":{"accountSid":{"type":"string","pattern":"^AC[0-9a-fA-F]{32}$"},"authToken":{"type":"string","pattern":"^[A-Za-z0-9]{16,64}$","description":"Solo escritura. Sin él se conserva el actual."},"numeroWhatsapp":{"type":"string","minLength":8,"maxLength":40,"example":"+18095551234"},"codigoSandbox":{"type":["string","null"],"maxLength":80,"example":"yellow-banana","description":"Código del sandbox de Twilio (lo que sigue a «join»); se acepta con o sin «join ». Vacío o null lo quita; sin enviarlo se conserva. No es secreto."}},"required":["accountSid","numeroWhatsapp"]},"ActivarWhatsappInput":{"type":"object","properties":{"activo":{"type":"boolean"}},"required":["activo"]},"PromoverWhatsappInput":{"type":"object","properties":{"empresaId":{"type":"string","format":"uuid"},"cambiarEmpresa":{"type":"boolean","default":false}},"required":["empresaId"]},"LimiteWhatsappInput":{"type":"object","properties":{"sinLimite":{"type":"boolean","default":false},"limiteFacturas":{"type":["integer","null"],"minimum":0,"maximum":1000000,"default":null}}},"PlantillaWhatsappInput":{"type":"object","properties":{"contentSid":{"anyOf":[{"type":"string","pattern":"^HX[0-9a-fA-F]{32}$"},{"type":"string","enum":[""]},{"type":"null"}],"default":null},"estado":{"type":"string","enum":["pendiente","aprobada","rechazada"],"default":"aprobada"},"texto":{"type":"string","maxLength":1024}}},"CuentaCreada":{"type":"object","properties":{"cuentaId":{"type":"string","format":"uuid"},"empresaId":{"type":"string","format":"uuid"},"apiKey":{"type":"string","description":"sk_test_… Solo se muestra una vez"},"ambiente":{"type":"string","enum":["sandbox"]}},"required":["cuentaId","empresaId","apiKey","ambiente"]},"CrearCuentaInput":{"type":"object","properties":{"nombre":{"type":"string","minLength":2,"maxLength":100},"correo":{"type":"string","format":"email"},"empresa":{"type":"string","minLength":2,"maxLength":150},"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"tipo":{"type":"string","enum":["empresa","integrador","contador"],"default":"empresa"}},"required":["nombre","correo","empresa"]},"SesionCreada":{"type":"object","properties":{"token":{"type":"string","description":"ses_… Guárdalo en una cookie httpOnly; nunca en localStorage"},"venceEn":{"type":"string"},"usuario":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nombre":{"type":"string"},"correo":{"type":"string"},"rol":{"type":"string","enum":["dueno","admin","facturador","lectura"]}},"required":["id","nombre","correo","rol"]},"cuentaId":{"type":"string","format":"uuid"},"empresas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"rnc":{"type":"string"},"razonSocial":{"type":"string"},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"esPrincipal":{"type":"boolean"}},"required":["id","rnc","razonSocial","ambiente","esPrincipal"]}}},"required":["token","venceEn","usuario","cuentaId","empresas"]},"RegistroInput":{"type":"object","properties":{"nombre":{"type":"string","minLength":2,"maxLength":100},"correo":{"type":"string","format":"email"},"password":{"type":"string","minLength":10,"maxLength":200},"empresa":{"type":"string","minLength":2,"maxLength":150},"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"tipo":{"type":"string","enum":["empresa","integrador","contador"],"default":"empresa"}},"required":["nombre","correo","password","empresa"]},"LoginInput":{"type":"object","properties":{"correo":{"type":"string","format":"email"},"password":{"type":"string","minLength":1,"maxLength":200}},"required":["correo","password"]},"Yo":{"type":"object","properties":{"usuario":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nombre":{"type":"string"},"correo":{"type":"string"},"rol":{"type":"string","enum":["dueno","admin","facturador","lectura"]}},"required":["id","nombre","correo","rol"]},"cuentaId":{"type":"string","format":"uuid"},"tipoCuenta":{"type":"string","enum":["empresa","integrador","contador"]},"empresas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"rnc":{"type":"string"},"razonSocial":{"type":"string"},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"esPrincipal":{"type":"boolean"}},"required":["id","rnc","razonSocial","ambiente","esPrincipal"]}},"suspension":{"type":["object","null"],"properties":{"motivo":{"type":["string","null"]},"desde":{"type":["string","null"]}},"required":["motivo","desde"]},"esAdministrador":{"type":"boolean"}},"required":["usuario","cuentaId","tipoCuenta","empresas"]},"OlvidePasswordInput":{"type":"object","properties":{"correo":{"type":"string","format":"email"}},"required":["correo"]},"RestablecerPasswordInput":{"type":"object","properties":{"correo":{"type":"string","format":"email"},"codigo":{"type":"string","pattern":"^\\d{6}$"},"password":{"type":"string","minLength":10,"maxLength":200}},"required":["correo","codigo","password"]},"CambiarPasswordInput":{"type":"object","properties":{"actual":{"type":"string","minLength":1,"maxLength":200},"nueva":{"type":"string","minLength":10,"maxLength":200}},"required":["actual","nueva"]},"ApiKeyResumen":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nombre":{"type":"string"},"prefijo":{"type":"string"},"ambiente":{"type":"string","enum":["sandbox","prod"]},"ultimoUso":{"type":["string","null"]},"creadoEn":{"type":"string"}},"required":["id","nombre","prefijo","ambiente","ultimoUso","creadoEn"]},"ApiKeyCreada":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"apiKey":{"type":"string"}},"required":["id","apiKey"]},"CrearApiKeyInput":{"type":"object","properties":{"nombre":{"type":"string","minLength":1,"maxLength":100},"ambiente":{"type":"string","enum":["sandbox","prod"]}},"required":["nombre","ambiente"]},"Cliente":{"type":"object","properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"identificadorExtranjero":{"type":"string","maxLength":20},"razonSocial":{"type":"string","minLength":1,"maxLength":150},"correo":{"type":"string","format":"email"},"telefono":{"type":"string","maxLength":12},"direccion":{"type":"string","maxLength":100},"municipio":{"type":"string"},"provincia":{"type":"string"},"id":{"type":"string","format":"uuid"},"creadoEn":{"type":"string"}},"required":["razonSocial","id","creadoEn"]},"ClienteInput":{"type":"object","properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"identificadorExtranjero":{"type":"string","maxLength":20},"razonSocial":{"type":"string","minLength":1,"maxLength":150},"correo":{"type":"string","format":"email"},"telefono":{"type":"string","maxLength":12},"direccion":{"type":"string","maxLength":100},"municipio":{"type":"string"},"provincia":{"type":"string"}},"required":["razonSocial"]},"ClienteParcial":{"type":"object","properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"identificadorExtranjero":{"type":"string","maxLength":20},"razonSocial":{"type":"string","minLength":1,"maxLength":150},"correo":{"type":"string","format":"email"},"telefono":{"type":"string","maxLength":12},"direccion":{"type":"string","maxLength":100},"municipio":{"type":"string"},"provincia":{"type":"string"}}},"Producto":{"type":"object","properties":{"codigo":{"type":"string","maxLength":35},"descripcion":{"type":"string","minLength":1,"maxLength":80},"precioUnitario":{"type":"number","minimum":0},"indicadorFacturacion":{"anyOf":[{"type":"number","enum":[0]},{"type":"number","enum":[1]},{"type":"number","enum":[2]},{"type":"number","enum":[3]},{"type":"number","enum":[4]}],"default":1},"indicadorBienServicio":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]}],"default":1},"unidadMedida":{"type":"string"},"id":{"type":"string","format":"uuid"},"creadoEn":{"type":"string"}},"required":["descripcion","precioUnitario","id","creadoEn"]},"ProductoInput":{"type":"object","properties":{"codigo":{"type":"string","maxLength":35},"descripcion":{"type":"string","minLength":1,"maxLength":80},"precioUnitario":{"type":"number","minimum":0},"indicadorFacturacion":{"anyOf":[{"type":"number","enum":[0]},{"type":"number","enum":[1]},{"type":"number","enum":[2]},{"type":"number","enum":[3]},{"type":"number","enum":[4]}],"default":1},"indicadorBienServicio":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]}],"default":1},"unidadMedida":{"type":"string"}},"required":["descripcion","precioUnitario"]},"ProductoParcial":{"type":"object","properties":{"codigo":{"type":"string","maxLength":35},"descripcion":{"type":"string","minLength":1,"maxLength":80},"precioUnitario":{"type":"number","minimum":0},"indicadorFacturacion":{"anyOf":[{"type":"number","enum":[0]},{"type":"number","enum":[1]},{"type":"number","enum":[2]},{"type":"number","enum":[3]},{"type":"number","enum":[4]}],"default":1},"indicadorBienServicio":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]}],"default":1},"unidadMedida":{"type":"string"}}},"Resumen":{"type":"object","properties":{"mes":{"type":"string","description":"AAAA-MM"},"ecf":{"type":"object","properties":{"total":{"type":"number"},"aceptados":{"type":"number"},"condicionales":{"type":"number"},"rechazados":{"type":"number"},"enProceso":{"type":"number"},"montoTotal":{"type":"number"},"totalItbis":{"type":"number"}},"required":["total","aceptados","condicionales","rechazados","enProceso","montoTotal","totalItbis"]},"requierenAtencion":{"type":"object","properties":{"total":{"type":"number"},"error":{"type":"number","description":"No llegaron a la DGII: reintentar el envío"},"rechazados":{"type":"number","description":"Rechazados sin corregir"},"pendientes":{"type":"number","description":"En cola más de 5 minutos"},"enProceso":{"type":"number","description":"Esperando a la DGII más de 10 minutos"}},"required":["total","error","rechazados","pendientes","enProceso"],"description":"e-CF que necesitan una acción del usuario (de cualquier fecha)"},"recibidosPendientes":{"type":"number"},"secuenciasPorAgotarse":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"number","enum":[31]},"restantes":{"type":"number"}},"required":["tipo","restantes"]}},"certificado":{"type":"object","properties":{"cargado":{"type":"boolean"},"venceEn":{"type":["string","null"]},"diasRestantes":{"type":["number","null"]}},"required":["cargado","venceEn","diasRestantes"]},"certificacion":{"type":"object","properties":{"pasoActual":{"type":"number"},"completada":{"type":"boolean"}},"required":["pasoActual","completada"]}},"required":["mes","ecf","requierenAtencion","recibidosPendientes","secuenciasPorAgotarse","certificado","certificacion"]},"Ecf":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"encf":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$"},"tipo":{"type":"number","enum":[31]},"estado":{"type":"string","enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error"]},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"esRfce":{"type":"boolean","description":"true si es factura de consumo < RD$250,000 enviada como resumen"},"trackId":{"type":["string","null"]},"codigoSeguridad":{"type":["string","null"],"description":"6 primeros caracteres del SignatureValue"},"fechaEmision":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"fechaFirma":{"type":["string","null"]},"comprador":{"type":["object","null"],"properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"identificadorExtranjero":{"type":"string","maxLength":20},"razonSocial":{"type":"string","maxLength":150},"correo":{"type":"string","format":"email"},"direccion":{"type":"string","maxLength":100},"municipio":{"type":"string","description":"Código DGII de municipio (6 dígitos)"},"provincia":{"type":"string","description":"Código DGII de provincia (6 dígitos)"},"telefono":{"type":"string","maxLength":12}}},"montoGravadoTotal":{"type":"number"},"montoExento":{"type":"number"},"totalItbis":{"type":"number"},"montoTotal":{"type":"number"},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}},"urls":{"type":"object","properties":{"xml":{"type":"string"},"pdf":{"type":"string"},"qr":{"type":"string"},"consultaDgii":{"type":["string","null"]}},"required":["xml","pdf","qr","consultaDgii"]},"idExterno":{"type":["string","null"]},"metadata":{"type":["object","null"],"additionalProperties":{"type":"string"}},"canal":{"type":["string","null"],"enum":["portal","api","sdk","mcp","sheets","whatsapp","excel","certificacion",null],"description":"Canal por el que se creó el e-CF; null en los emitidos antes del seguimiento de canales. sdk, mcp y sheets los declara el cliente"},"reemplazaA":{"type":["string","null"],"format":"uuid","description":"Si este e-CF corrige a un rechazado con e-NCF nuevo: id del rechazado"},"reemplazadoPor":{"type":["string","null"],"format":"uuid","description":"Si este e-CF fue rechazado y ya se corrigió con otro e-NCF: id del nuevo"},"secuenciaReutilizable":{"type":["boolean","null"],"description":"Solo en rechazados: true si la DGII permite reusar el e-NCF (secuenciaUtilizada = false)"},"requiereAtencion":{"type":"boolean","description":"true si está en error, rechazado sin corregir, o pendiente / en proceso sin avanzar"},"creadoEn":{"type":"string"},"actualizadoEn":{"type":"string"}},"required":["id","encf","tipo","estado","ambiente","esRfce","trackId","codigoSeguridad","fechaEmision","fechaFirma","comprador","montoGravadoTotal","montoExento","totalItbis","montoTotal","mensajes","urls","idExterno","metadata","canal","reemplazaA","reemplazadoPor","secuenciaReutilizable","requiereAtencion","creadoEn","actualizadoEn"]},"EmitirEcfInput":{"type":"object","properties":{"tipo":{"type":"number","enum":[31]},"encf":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$","description":"Si se omite, Firmo asigna la siguiente secuencia disponible"},"fechaEmision":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Por defecto: hoy en America/Santo_Domingo"},"tipoIngresos":{"type":"string","enum":["01","02","03","04","05","06"],"default":"01"},"tipoPago":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]},{"type":"number","enum":[3]}],"default":1},"fechaLimitePago":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"terminoPago":{"type":"string","maxLength":15},"formasPago":{"type":"array","items":{"type":"object","properties":{"forma":{"type":"integer","minimum":1,"maximum":8},"monto":{"type":"number","minimum":0}},"required":["forma","monto"]},"maxItems":7},"comprador":{"type":"object","properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"identificadorExtranjero":{"type":"string","maxLength":20},"razonSocial":{"type":"string","maxLength":150},"correo":{"type":"string","format":"email"},"direccion":{"type":"string","maxLength":100},"municipio":{"type":"string","description":"Código DGII de municipio (6 dígitos)"},"provincia":{"type":"string","description":"Código DGII de provincia (6 dígitos)"},"telefono":{"type":"string","maxLength":12}}},"items":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string","maxLength":35},"descripcion":{"type":"string","minLength":1,"maxLength":80},"cantidad":{"type":"number","exclusiveMinimum":0},"unidadMedida":{"type":"string","description":"Código de unidad de medida DGII"},"precioUnitario":{"type":"number","minimum":0},"descuento":{"type":"number","minimum":0},"indicadorFacturacion":{"anyOf":[{"type":"number","enum":[0]},{"type":"number","enum":[1]},{"type":"number","enum":[2]},{"type":"number","enum":[3]},{"type":"number","enum":[4]}],"default":1},"indicadorBienServicio":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]}],"default":1},"retencion":{"type":"object","properties":{"indicadorAgente":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]}],"description":"1 Retención, 2 Percepción"},"montoItbisRetenido":{"type":"number","minimum":0},"montoIsrRetenido":{"type":"number","minimum":0}},"required":["indicadorAgente"]}},"required":["descripcion","cantidad","precioUnitario"]},"minItems":1,"maxItems":1000},"referencia":{"type":"object","properties":{"encfModificado":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$"},"fechaModificado":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"codigoModificacion":{"type":"integer","minimum":1,"maximum":5},"razon":{"type":"string","maxLength":90}},"required":["encfModificado","fechaModificado","codigoModificacion"],"description":"Obligatoria en notas de débito (33) y crédito (34)"},"moneda":{"type":"object","properties":{"tipo":{"type":"string","minLength":3,"maxLength":3},"tasaCambio":{"type":"number","exclusiveMinimum":0}},"required":["tipo","tasaCambio"]},"idExterno":{"type":"string","maxLength":100,"description":"Tu identificador interno (único por empresa)"},"enviarCorreo":{"type":"boolean","default":false,"description":"Enviar el PDF al correo del comprador"},"metadata":{"type":"object","additionalProperties":{"type":"string"}}},"required":["tipo","items"]},"PaginadoEcf":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/Ecf"}},"siguiente":{"type":["string","null"]}},"required":["datos","siguiente"]},"ResultadoConsultaEcf":{"type":"object","properties":{"ecf":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"encf":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$"},"tipo":{"type":"number","enum":[31]},"estado":{"type":"string","enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error"]},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"esRfce":{"type":"boolean","description":"true si es factura de consumo < RD$250,000 enviada como resumen"},"trackId":{"type":["string","null"]},"codigoSeguridad":{"type":["string","null"],"description":"6 primeros caracteres del SignatureValue"},"fechaEmision":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"fechaFirma":{"type":["string","null"]},"comprador":{"type":["object","null"],"properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"identificadorExtranjero":{"type":"string","maxLength":20},"razonSocial":{"type":"string","maxLength":150},"correo":{"type":"string","format":"email"},"direccion":{"type":"string","maxLength":100},"municipio":{"type":"string","description":"Código DGII de municipio (6 dígitos)"},"provincia":{"type":"string","description":"Código DGII de provincia (6 dígitos)"},"telefono":{"type":"string","maxLength":12}}},"montoGravadoTotal":{"type":"number"},"montoExento":{"type":"number"},"totalItbis":{"type":"number"},"montoTotal":{"type":"number"},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}},"urls":{"type":"object","properties":{"xml":{"type":"string"},"pdf":{"type":"string"},"qr":{"type":"string"},"consultaDgii":{"type":["string","null"]}},"required":["xml","pdf","qr","consultaDgii"]},"idExterno":{"type":["string","null"]},"metadata":{"type":["object","null"],"additionalProperties":{"type":"string"}},"canal":{"type":["string","null"],"enum":["portal","api","sdk","mcp","sheets","whatsapp","excel","certificacion",null],"description":"Canal por el que se creó el e-CF; null en los emitidos antes del seguimiento de canales. sdk, mcp y sheets los declara el cliente"},"reemplazaA":{"type":["string","null"],"format":"uuid","description":"Si este e-CF corrige a un rechazado con e-NCF nuevo: id del rechazado"},"reemplazadoPor":{"type":["string","null"],"format":"uuid","description":"Si este e-CF fue rechazado y ya se corrigió con otro e-NCF: id del nuevo"},"secuenciaReutilizable":{"type":["boolean","null"],"description":"Solo en rechazados: true si la DGII permite reusar el e-NCF (secuenciaUtilizada = false)"},"requiereAtencion":{"type":"boolean","description":"true si está en error, rechazado sin corregir, o pendiente / en proceso sin avanzar"},"creadoEn":{"type":"string"},"actualizadoEn":{"type":"string"}},"required":["id","encf","tipo","estado","ambiente","esRfce","trackId","codigoSeguridad","fechaEmision","fechaFirma","comprador","montoGravadoTotal","montoExento","totalItbis","montoTotal","mensajes","urls","idExterno","metadata","canal","reemplazaA","reemplazadoPor","secuenciaReutilizable","requiereAtencion","creadoEn","actualizadoEn"]},"resultado":{"type":"string","enum":["ok","sin_cambio","error","rechazado","encolado"]},"detalle":{"type":"string"}},"required":["ecf","resultado","detalle"]},"CorregirEcfResultado":{"type":"object","properties":{"regla":{"type":"string","enum":["mismo_encf","encf_nuevo"],"description":"mismo_encf: se reusó el e-NCF del rechazado; encf_nuevo: e-NCF nuevo, el rechazado queda enlazado"},"motivo":{"type":"string"},"ecf":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"encf":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$"},"tipo":{"type":"number","enum":[31]},"estado":{"type":"string","enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error"]},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"esRfce":{"type":"boolean","description":"true si es factura de consumo < RD$250,000 enviada como resumen"},"trackId":{"type":["string","null"]},"codigoSeguridad":{"type":["string","null"],"description":"6 primeros caracteres del SignatureValue"},"fechaEmision":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"fechaFirma":{"type":["string","null"]},"comprador":{"type":["object","null"],"properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"identificadorExtranjero":{"type":"string","maxLength":20},"razonSocial":{"type":"string","maxLength":150},"correo":{"type":"string","format":"email"},"direccion":{"type":"string","maxLength":100},"municipio":{"type":"string","description":"Código DGII de municipio (6 dígitos)"},"provincia":{"type":"string","description":"Código DGII de provincia (6 dígitos)"},"telefono":{"type":"string","maxLength":12}}},"montoGravadoTotal":{"type":"number"},"montoExento":{"type":"number"},"totalItbis":{"type":"number"},"montoTotal":{"type":"number"},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}},"urls":{"type":"object","properties":{"xml":{"type":"string"},"pdf":{"type":"string"},"qr":{"type":"string"},"consultaDgii":{"type":["string","null"]}},"required":["xml","pdf","qr","consultaDgii"]},"idExterno":{"type":["string","null"]},"metadata":{"type":["object","null"],"additionalProperties":{"type":"string"}},"canal":{"type":["string","null"],"enum":["portal","api","sdk","mcp","sheets","whatsapp","excel","certificacion",null],"description":"Canal por el que se creó el e-CF; null en los emitidos antes del seguimiento de canales. sdk, mcp y sheets los declara el cliente"},"reemplazaA":{"type":["string","null"],"format":"uuid","description":"Si este e-CF corrige a un rechazado con e-NCF nuevo: id del rechazado"},"reemplazadoPor":{"type":["string","null"],"format":"uuid","description":"Si este e-CF fue rechazado y ya se corrigió con otro e-NCF: id del nuevo"},"secuenciaReutilizable":{"type":["boolean","null"],"description":"Solo en rechazados: true si la DGII permite reusar el e-NCF (secuenciaUtilizada = false)"},"requiereAtencion":{"type":"boolean","description":"true si está en error, rechazado sin corregir, o pendiente / en proceso sin avanzar"},"creadoEn":{"type":"string"},"actualizadoEn":{"type":"string"}},"required":["id","encf","tipo","estado","ambiente","esRfce","trackId","codigoSeguridad","fechaEmision","fechaFirma","comprador","montoGravadoTotal","montoExento","totalItbis","montoTotal","mensajes","urls","idExterno","metadata","canal","reemplazaA","reemplazadoPor","secuenciaReutilizable","requiereAtencion","creadoEn","actualizadoEn"]},"original":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid"},"encf":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$"},"tipo":{"type":"number","enum":[31]},"estado":{"type":"string","enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error"]},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"esRfce":{"type":"boolean","description":"true si es factura de consumo < RD$250,000 enviada como resumen"},"trackId":{"type":["string","null"]},"codigoSeguridad":{"type":["string","null"],"description":"6 primeros caracteres del SignatureValue"},"fechaEmision":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"fechaFirma":{"type":["string","null"]},"comprador":{"type":["object","null"],"properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"identificadorExtranjero":{"type":"string","maxLength":20},"razonSocial":{"type":"string","maxLength":150},"correo":{"type":"string","format":"email"},"direccion":{"type":"string","maxLength":100},"municipio":{"type":"string","description":"Código DGII de municipio (6 dígitos)"},"provincia":{"type":"string","description":"Código DGII de provincia (6 dígitos)"},"telefono":{"type":"string","maxLength":12}}},"montoGravadoTotal":{"type":"number"},"montoExento":{"type":"number"},"totalItbis":{"type":"number"},"montoTotal":{"type":"number"},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}},"urls":{"type":"object","properties":{"xml":{"type":"string"},"pdf":{"type":"string"},"qr":{"type":"string"},"consultaDgii":{"type":["string","null"]}},"required":["xml","pdf","qr","consultaDgii"]},"idExterno":{"type":["string","null"]},"metadata":{"type":["object","null"],"additionalProperties":{"type":"string"}},"canal":{"type":["string","null"],"enum":["portal","api","sdk","mcp","sheets","whatsapp","excel","certificacion",null],"description":"Canal por el que se creó el e-CF; null en los emitidos antes del seguimiento de canales. sdk, mcp y sheets los declara el cliente"},"reemplazaA":{"type":["string","null"],"format":"uuid","description":"Si este e-CF corrige a un rechazado con e-NCF nuevo: id del rechazado"},"reemplazadoPor":{"type":["string","null"],"format":"uuid","description":"Si este e-CF fue rechazado y ya se corrigió con otro e-NCF: id del nuevo"},"secuenciaReutilizable":{"type":["boolean","null"],"description":"Solo en rechazados: true si la DGII permite reusar el e-NCF (secuenciaUtilizada = false)"},"requiereAtencion":{"type":"boolean","description":"true si está en error, rechazado sin corregir, o pendiente / en proceso sin avanzar"},"creadoEn":{"type":"string"},"actualizadoEn":{"type":"string"}},"required":["id","encf","tipo","estado","ambiente","esRfce","trackId","codigoSeguridad","fechaEmision","fechaFirma","comprador","montoGravadoTotal","montoExento","totalItbis","montoTotal","mensajes","urls","idExterno","metadata","canal","reemplazaA","reemplazadoPor","secuenciaReutilizable","requiereAtencion","creadoEn","actualizadoEn"],"description":"El rechazado (solo con encf_nuevo)"}},"required":["regla","motivo","ecf","original"]},"IntentoEcf":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"accion":{"type":"string","enum":["envio","reenvio","consulta","correccion"],"description":"envio: automático; reenvio: reenvío del mismo XML; consulta: consulta del estado a la DGII; correccion: reemisión de un rechazado"},"origen":{"type":"string","description":"automatico, portal, api, sdk, mcp, whatsapp…"},"estadoAntes":{"type":["string","null"],"enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error",null]},"estadoDespues":{"type":["string","null"],"enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error",null]},"resultado":{"type":"string","enum":["ok","sin_cambio","error","rechazado","encolado"]},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}},"detalle":{"type":["string","null"]},"creadoEn":{"type":"string"}},"required":["id","accion","origen","estadoAntes","estadoDespues","resultado","mensajes","detalle","creadoEn"]},"ReenvioLote":{"type":"object","properties":{"total":{"type":"integer"},"reenviados":{"type":"integer"},"omitidos":{"type":"integer"},"resultados":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"encf":{"type":"string"},"estadoAntes":{"type":"string","enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error"]},"estadoDespues":{"type":"string","enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error"]},"resultado":{"type":"string","enum":["ok","sin_cambio","error","rechazado","encolado"]},"detalle":{"type":"string"}},"required":["id","encf","estadoAntes","estadoDespues","resultado","detalle"]}}},"required":["total","reenviados","omitidos","resultados"]},"EnviarCorreoInput":{"type":"object","properties":{"correo":{"type":"string","format":"email"}},"required":["correo"]},"Importacion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"estado":{"type":"string","enum":["validado","con_errores","emitiendo","completado"],"description":"`validado`: lista para emitir · `con_errores`: no se puede emitir · `emitiendo`: en la cola · `completado`: todas las facturas tienen su resultado final"},"nombreArchivo":{"type":"string"},"formato":{"type":"string","enum":["xlsx","csv"]},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"resumen":{"type":"object","properties":{"facturas":{"type":"integer"},"items":{"type":"integer"},"montoTotal":{"type":"number"},"totalItbis":{"type":"number"}},"required":["facturas","items","montoTotal","totalItbis"]},"errores":{"type":"array","items":{"$ref":"#/components/schemas/ErrorImportacion"},"description":"Errores que no son de una factura (p. ej. ítems de Detalle cuya referencia no está en Facturas)"},"progreso":{"type":"object","properties":{"total":{"type":"integer"},"procesadas":{"type":"integer"},"terminadas":{"type":"integer"},"aceptadas":{"type":"integer"},"rechazadas":{"type":"integer"},"conError":{"type":"integer"},"yaEmitidas":{"type":"integer"},"enProceso":{"type":"integer"}},"required":["total","procesadas","terminadas","aceptadas","rechazadas","conError","yaEmitidas","enProceso"]},"filas":{"type":"array","items":{"type":"object","properties":{"referencia":{"type":"string"},"hoja":{"type":"string"},"fila":{"type":"integer"},"tipo":{"type":["integer","null"]},"comprador":{"type":["string","null"]},"montoTotal":{"type":"number"},"totalItbis":{"type":"number"},"items":{"type":"integer"},"errores":{"type":"array","items":{"$ref":"#/components/schemas/ErrorImportacion"}},"resultado":{"$ref":"#/components/schemas/ResultadoImportacion"}},"required":["referencia","hoja","fila","tipo","comprador","montoTotal","totalItbis","items","errores","resultado"]}},"creadoEn":{"type":"string"},"actualizadoEn":{"type":"string"},"emitidoEn":{"type":["string","null"]},"completadoEn":{"type":["string","null"]}},"required":["id","estado","nombreArchivo","formato","ambiente","resumen","errores","progreso","filas","creadoEn","actualizadoEn","emitidoEn","completadoEn"]},"ErrorImportacion":{"type":"object","properties":{"hoja":{"type":"string","example":"Detalle"},"fila":{"type":["integer","null"],"description":"Fila del Excel o del CSV (1 = encabezados)","example":4},"columna":{"type":["string","null"],"example":"precio_unitario"},"mensaje":{"type":"string","example":"«mil» no es un número"}},"required":["hoja","fila","columna","mensaje"]},"ResultadoImportacion":{"type":["object","null"],"properties":{"id":{"type":["string","null"],"description":"id del e-CF"},"encf":{"type":["string","null"]},"estado":{"type":"string","enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error","ya_emitida","no_emitida"],"description":"Estado del e-CF, o `ya_emitida` (la referencia ya existía: no se duplicó) o `no_emitida` (Firmo no pudo crearla, p. ej. secuencia agotada)"},"mensaje":{"type":["string","null"]},"pdf":{"type":["string","null"],"description":"URL de la representación impresa (requiere Authorization)"}},"required":["id","encf","estado","mensaje","pdf"]},"PaginadoImportacion":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/ResumenImportacion"}},"siguiente":{"type":["string","null"]}},"required":["datos","siguiente"]},"ResumenImportacion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"estado":{"type":"string","enum":["validado","con_errores","emitiendo","completado"],"description":"`validado`: lista para emitir · `con_errores`: no se puede emitir · `emitiendo`: en la cola · `completado`: todas las facturas tienen su resultado final"},"nombreArchivo":{"type":"string"},"formato":{"type":"string","enum":["xlsx","csv"]},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"resumen":{"type":"object","properties":{"facturas":{"type":"integer"},"items":{"type":"integer"},"montoTotal":{"type":"number"},"totalItbis":{"type":"number"}},"required":["facturas","items","montoTotal","totalItbis"]},"conErrores":{"type":"integer","description":"Facturas con errores (+1 si hay errores generales)"},"creadoEn":{"type":"string"},"emitidoEn":{"type":["string","null"]},"completadoEn":{"type":["string","null"]}},"required":["id","estado","nombreArchivo","formato","ambiente","resumen","conErrores","creadoEn","emitidoEn","completadoEn"]},"Anulacion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"rangos":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"number","enum":[31]},"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["tipo","desde","hasta"]}},"estado":{"type":"string","enum":["pendiente","aceptado","rechazado","error"]},"trackId":{"type":["string","null"]},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}},"creadoEn":{"type":"string"}},"required":["id","rangos","estado","trackId","mensajes","creadoEn"]},"AnularInput":{"type":"object","properties":{"rangos":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"number","enum":[31]},"desde":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$"},"hasta":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$"}},"required":["tipo","desde","hasta"]},"minItems":1,"maxItems":10}},"required":["rangos"]},"PaginadoRecibido":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/Recibido"}},"siguiente":{"type":["string","null"]}},"required":["datos","siguiente"]},"Recibido":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"encf":{"type":"string","pattern":"^E(31|32|33|34|41|43|44|45|46|47)\\d{10}$"},"rncEmisor":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"razonSocialEmisor":{"type":["string","null"]},"fechaEmision":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"montoTotal":{"type":"number"},"totalItbis":{"type":"number"},"acuse":{"type":"string","enum":["recibido","no_recibido"]},"aprobacion":{"type":"string","enum":["pendiente","aprobado","rechazado"]},"motivoRechazo":{"type":["string","null"]},"urls":{"type":"object","properties":{"xml":{"type":"string"}},"required":["xml"]},"recibidoEn":{"type":"string"}},"required":["id","encf","rncEmisor","razonSocialEmisor","fechaEmision","montoTotal","totalItbis","acuse","aprobacion","motivoRechazo","urls","recibidoEn"]},"AprobacionInput":{"type":"object","properties":{"aprobado":{"type":"boolean"},"motivo":{"type":"string","maxLength":250,"description":"Obligatorio si aprobado = false"}},"required":["aprobado"]},"Empresa":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"razonSocial":{"type":"string"},"nombreComercial":{"type":["string","null"]},"direccion":{"type":["string","null"]},"municipio":{"type":["string","null"]},"provincia":{"type":["string","null"]},"telefono":{"type":["string","null"]},"correo":{"type":["string","null"]},"sitioWeb":{"type":["string","null"]},"actividadEconomica":{"type":["string","null"]},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"certificado":{"type":"object","properties":{"cargado":{"type":"boolean"},"titular":{"type":["string","null"]},"venceEn":{"type":["string","null"]}},"required":["cargado","titular","venceEn"]},"creadoEn":{"type":"string"}},"required":["id","rnc","razonSocial","nombreComercial","direccion","municipio","provincia","telefono","correo","sitioWeb","actividadEconomica","ambiente","certificado","creadoEn"]},"ActualizarEmpresaInput":{"type":"object","properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"razonSocial":{"type":"string"},"nombreComercial":{"type":"string"},"direccion":{"type":"string"},"municipio":{"type":"string"},"provincia":{"type":"string"},"telefono":{"type":"string"},"correo":{"type":"string","format":"email"},"sitioWeb":{"type":"string"},"actividadEconomica":{"type":"string"},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"],"description":"`test` usa TesteCF real con tu certificado; `cert` y `prod` requieren llave sk_live_"}}},"SubirCertificadoInput":{"type":"object","properties":{"archivo":{"type":"string","format":"binary"},"password":{"type":"string","minLength":1}},"required":["archivo","password"]},"PaginadoEmpresa":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/Empresa"}},"siguiente":{"type":["string","null"]}},"required":["datos","siguiente"]},"CrearEmpresaInput":{"type":"object","properties":{"rnc":{"type":"string","pattern":"^(\\d{9}|\\d{11})$"},"razonSocial":{"type":"string"},"nombreComercial":{"type":"string"},"direccion":{"type":"string"},"municipio":{"type":"string"},"provincia":{"type":"string"},"telefono":{"type":"string"},"correo":{"type":"string","format":"email"},"sitioWeb":{"type":"string"},"actividadEconomica":{"type":"string"}},"required":["rnc","razonSocial"]},"FormatoFactura":{"type":"object","properties":{"papel":{"type":"string","enum":["carta","media_carta","termica_80","termica_58"],"description":"`carta` (8.5×11 in), `media_carta` (5.5×8.5 in), `termica_80` (80 mm) o `termica_58` (58 mm)"},"papelPorTipo":{"type":"object","additionalProperties":{"type":"string","enum":["carta","media_carta","termica_80","termica_58"],"description":"`carta` (8.5×11 in), `media_carta` (5.5×8.5 in), `termica_80` (80 mm) o `termica_58` (58 mm)"},"description":"Papel por tipo de e-CF, p. ej. `{\"32\":\"termica_80\",\"31\":\"carta\"}`. La térmica solo se admite en los tipos 31 y 32."},"logo":{"type":"object","properties":{"presente":{"type":"boolean"},"mime":{"type":["string","null"]},"url":{"type":["string","null"]}},"required":["presente","mime","url"]},"colorAcento":{"type":["string","null"],"example":"#006040","description":"#RRGGBB con contraste AA (4.5:1) sobre blanco; null usa el verde de la DGII"},"pieTexto":{"type":["string","null"],"description":"Texto plano de hasta 500 caracteres"},"mostrarCodigoItem":{"type":"boolean"},"mostrarUnidad":{"type":"boolean"},"mostrarDescuento":{"type":"boolean"},"marcaFirmo":{"type":"boolean","description":"Pie «Emitido con Firmo»"},"mensajesPorTipo":{"type":"object","additionalProperties":{"type":"string"},"description":"Mensaje fijo por tipo de e-CF (hasta 200 caracteres)"},"tiposConTermica":{"type":"array","items":{"type":"number"},"description":"Tipos de e-CF que admiten papel térmico según las reglas de la DGII"},"personalizado":{"type":"boolean","description":"false si la empresa aún no guardó un formato (se usa el predeterminado)"}},"required":["papel","papelPorTipo","logo","colorAcento","pieTexto","mostrarCodigoItem","mostrarUnidad","mostrarDescuento","marcaFirmo","mensajesPorTipo","tiposConTermica","personalizado"]},"ActualizarFormatoFactura":{"type":"object","properties":{"papel":{"type":"string","enum":["carta","media_carta","termica_80","termica_58"],"description":"`carta` (8.5×11 in), `media_carta` (5.5×8.5 in), `termica_80` (80 mm) o `termica_58` (58 mm)"},"papelPorTipo":{"type":"object","additionalProperties":{"type":"string","enum":["carta","media_carta","termica_80","termica_58"],"description":"`carta` (8.5×11 in), `media_carta` (5.5×8.5 in), `termica_80` (80 mm) o `termica_58` (58 mm)"}},"colorAcento":{"type":["string","null"]},"pieTexto":{"type":["string","null"]},"mostrarCodigoItem":{"type":"boolean"},"mostrarUnidad":{"type":"boolean"},"mostrarDescuento":{"type":"boolean"},"marcaFirmo":{"type":"boolean"},"mensajesPorTipo":{"type":"object","additionalProperties":{"type":"string"}}}},"SubirLogoInput":{"type":"object","properties":{"archivo":{"type":"string","format":"binary"}}},"PaginadoSecuencia":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/Secuencia"}},"siguiente":{"type":["string","null"]}},"required":["datos","siguiente"]},"Secuencia":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tipo":{"type":"number","enum":[31]},"desde":{"type":"integer"},"hasta":{"type":"integer"},"siguiente":{"type":"integer"},"venceEn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"estado":{"type":"string","enum":["activa","agotada","vencida","anulada"]}},"required":["id","tipo","desde","hasta","siguiente","venceEn","estado"]},"CrearSecuenciaInput":{"type":"object","properties":{"tipo":{"type":"number","enum":[31]},"desde":{"type":"integer","exclusiveMinimum":0},"hasta":{"type":"integer","exclusiveMinimum":0},"venceEn":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["tipo","desde","hasta","venceEn"]},"PaginadoWebhook":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"siguiente":{"type":["string","null"]}},"required":["datos","siguiente"]},"Webhook":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"eventos":{"type":"array","items":{"type":"string","enum":["ecf.aceptado","ecf.aceptado_condicional","ecf.rechazado","ecf.error","ecf.reintentado","recibido.nuevo","certificado.por_vencer","secuencia.por_agotarse"]},"minItems":1},"id":{"type":"string","format":"uuid"},"secreto":{"type":"string","description":"Solo se muestra al crear. Firma HMAC-SHA256 en el header Firmo-Signature"},"activo":{"type":"boolean"},"creadoEn":{"type":"string"}},"required":["url","eventos","id","secreto","activo","creadoEn"]},"CrearWebhookInput":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"eventos":{"type":"array","items":{"type":"string","enum":["ecf.aceptado","ecf.aceptado_condicional","ecf.rechazado","ecf.error","ecf.reintentado","recibido.nuevo","certificado.por_vencer","secuencia.por_agotarse"]},"minItems":1}},"required":["url","eventos"]},"EstadoDgii":{"type":"object","properties":{"estado":{"type":"string","enum":["aceptado","aceptado_condicional","rechazado","en_proceso"]},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}}},"required":["estado","mensajes"]},"ConsultaRnc":{"type":"object","properties":{"rnc":{"type":"string"},"razonSocial":{"type":"string"},"nombreComercial":{"type":["string","null"]},"estado":{"type":["string","null"]}},"required":["rnc","razonSocial","nombreComercial","estado"]},"ProgresoCertificacion":{"type":"object","properties":{"empresaId":{"type":"string","format":"uuid"},"rnc":{"type":"string"},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"]},"pasoActual":{"type":"number"},"completada":{"type":"boolean"},"urls":{"type":"object","properties":{"base":{"type":"string"},"semilla":{"type":"string"},"recepcion":{"type":"string"},"aprobacionComercial":{"type":"string"}},"required":["base","semilla","recepcion","aprobacionComercial"]},"pasos":{"type":"array","items":{"type":"object","properties":{"n":{"type":"integer","minimum":0,"maximum":15},"nombre":{"type":"string"},"tipo":{"type":"string","enum":["firmo","manual","automatico","espera","descarga","deteccion"]},"estado":{"type":"string","enum":["bloqueado","pendiente","en_progreso","completado","error"]},"instrucciones":{"type":"array","items":{"type":"string"},"description":"Pasos para el usuario, en español, en orden"},"enlaces":{"type":"array","items":{"type":"object","properties":{"texto":{"type":"string"},"url":{"type":"string"}},"required":["texto","url"]}},"artefactos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nombre":{"type":"string"},"tipo":{"type":"string","enum":["xml","zip","html","pdf"]},"url":{"type":"string","description":"Ruta relativa a la API: /v1/certification/artifacts/{id}"},"descripcion":{"type":"string"}},"required":["id","nombre","tipo","url"]}},"resultado":{"type":["object","null"],"properties":{"resumen":{"type":"string"},"contadores":{"type":"object","additionalProperties":{"type":"object","properties":{"ok":{"type":"number"},"total":{"type":"number"}},"required":["ok","total"]}},"envios":{"type":"array","items":{"type":"object","properties":{"encf":{"type":"string"},"tipo":{"type":"string","description":"31…47 o RFCE / ACECF"},"servidor":{"type":"string","enum":["ecf","fc"]},"trackId":{"type":["string","null"]},"estado":{"type":"string","enum":["pendiente","enviado","aceptado","aceptado_condicional","rechazado","error"]},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}}},"required":["encf","tipo","servidor","trackId","estado","mensajes"]}}},"required":["resumen"]},"actualizadoEn":{"type":["string","null"]}},"required":["n","nombre","tipo","estado","instrucciones","enlaces","artefactos","resultado","actualizadoEn"]}}},"required":["empresaId","rnc","ambiente","pasoActual","completada","urls","pasos"]},"PasoCertificacion":{"type":"object","properties":{"n":{"type":"integer","minimum":0,"maximum":15},"nombre":{"type":"string"},"tipo":{"type":"string","enum":["firmo","manual","automatico","espera","descarga","deteccion"]},"estado":{"type":"string","enum":["bloqueado","pendiente","en_progreso","completado","error"]},"instrucciones":{"type":"array","items":{"type":"string"},"description":"Pasos para el usuario, en español, en orden"},"enlaces":{"type":"array","items":{"type":"object","properties":{"texto":{"type":"string"},"url":{"type":"string"}},"required":["texto","url"]}},"artefactos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nombre":{"type":"string"},"tipo":{"type":"string","enum":["xml","zip","html","pdf"]},"url":{"type":"string","description":"Ruta relativa a la API: /v1/certification/artifacts/{id}"},"descripcion":{"type":"string"}},"required":["id","nombre","tipo","url"]}},"resultado":{"type":["object","null"],"properties":{"resumen":{"type":"string"},"contadores":{"type":"object","additionalProperties":{"type":"object","properties":{"ok":{"type":"number"},"total":{"type":"number"}},"required":["ok","total"]}},"envios":{"type":"array","items":{"type":"object","properties":{"encf":{"type":"string"},"tipo":{"type":"string","description":"31…47 o RFCE / ACECF"},"servidor":{"type":"string","enum":["ecf","fc"]},"trackId":{"type":["string","null"]},"estado":{"type":"string","enum":["pendiente","enviado","aceptado","aceptado_condicional","rechazado","error"]},"mensajes":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"valor":{"type":"string"}},"required":["codigo","valor"]}}},"required":["encf","tipo","servidor","trackId","estado","mensajes"]}}},"required":["resumen"]},"actualizadoEn":{"type":["string","null"]}},"required":["n","nombre","tipo","estado","instrucciones","enlaces","artefactos","resultado","actualizadoEn"]},"TokenReceptor":{"type":"object","properties":{"token":{"type":"string"},"expira":{"type":"string"},"expedido":{"type":"string"}},"required":["token","expira","expedido"]},"ConfigWhatsapp":{"type":"object","properties":{"configurado":{"type":"boolean","description":"false si la empresa todavía no guardó su cuenta de Twilio"},"activo":{"type":"boolean","description":"false si se desconectó (el webhook responde 410)"},"estado":{"type":"string","enum":["sin_configurar","sin_probar","conectado","error","desconectado"]},"ultimoError":{"type":["string","null"],"description":"Motivo legible de la última prueba fallida"},"verificadoEn":{"type":["string","null"],"description":"Última prueba de conexión exitosa"},"accountSid":{"type":["string","null"]},"authTokenFinal":{"type":["string","null"],"description":"Últimos 4 caracteres del Auth Token. El token nunca se devuelve."},"numeroWhatsapp":{"type":["string","null"],"description":"Remitente en E.164 (+14155238886)"},"plantillaCodigoSid":{"type":["string","null"]},"codigoSandbox":{"type":["string","null"],"description":"Código del sandbox de Twilio (sin «join »), si se usa el número del sandbox"},"webhookUrl":{"type":["string","null"],"description":"Pégala en Twilio como «When a message comes in» (POST)"},"numeroSandbox":{"type":"string","description":"Número del sandbox de Twilio"},"instrucciones":{"type":"object","properties":{"sandbox":{"type":"array","items":{"type":"string"}},"produccion":{"type":"array","items":{"type":"string"}}},"required":["sandbox","produccion"],"description":"Pasos en texto; lo que va entre `…` es literal"}},"required":["configurado","activo","estado","ultimoError","verificadoEn","accountSid","authTokenFinal","numeroWhatsapp","plantillaCodigoSid","codigoSandbox","webhookUrl","numeroSandbox","instrucciones"]},"GuardarConfigWhatsappInput":{"type":"object","properties":{"accountSid":{"type":"string","pattern":"^AC[0-9a-fA-F]{32}$","example":"AC0123456789abcdef0123456789abcdef"},"authToken":{"type":"string","pattern":"^[A-Za-z0-9]{16,64}$","description":"Si no se envía, se conserva el actual. Nunca se devuelve."},"numeroWhatsapp":{"type":"string","minLength":8,"maxLength":40,"example":"+14155238886","description":"E.164; se acepta con o sin el prefijo whatsapp:"},"codigoSandbox":{"type":["string","null"],"maxLength":80,"example":"yellow-banana","description":"Código del sandbox de Twilio (lo que sigue a «join»); con o sin «join ». Vacío o null lo quita; sin enviarlo se conserva."},"plantillaCodigoSid":{"type":["string","null"],"pattern":"^HX[0-9a-fA-F]{32}$","description":"ContentSid de la plantilla del código de verificación (Authentication). null lo quita."}},"required":["accountSid","numeroWhatsapp"]},"EstadoWhatsapp":{"type":"object","properties":{"modo":{"type":"string","enum":["firmo","propio"],"description":"firmo = WhatsApp de Firmo (número de la plataforma, por defecto); propio = tu propia cuenta de Twilio"},"habilitado":{"type":"boolean","description":"true si el canal puede atender hoy: en modo firmo, el WhatsApp de la plataforma está configurado y activo; en modo propio, la cuenta de Twilio de la empresa está conectada"},"motivo":{"type":["string","null"]},"plataformaDisponible":{"type":"boolean","description":"true si el WhatsApp de Firmo está configurado y activo"},"configuracion":{"type":"string","enum":["sin_configurar","sin_probar","conectado","error","desconectado"],"description":"Estado de la cuenta de Twilio PROPIA de la empresa (solo importa en modo propio)"},"numeroWhatsapp":{"type":["string","null"],"description":"Número de WhatsApp al que se escribe, en E.164: el de Firmo o el propio según el modo"},"enlaceWhatsapp":{"type":["string","null"],"description":"https://wa.me/… para abrir el chat"},"esSandbox":{"type":"boolean","description":"true si el número efectivo es el del sandbox de Twilio: quien pruebe debe enviarle antes `join <código>` (la unión vence tras ~3 días sin escribir)"},"codigoSandbox":{"type":["string","null"],"description":"Código del sandbox (sin «join ») configurado para el modo efectivo; null si falta"},"interprete":{"type":"string","enum":["claude","respaldo"],"description":"claude = lenguaje natural; respaldo = formato fijo"},"numeros":{"type":"object","properties":{"total":{"type":"integer"},"activos":{"type":"integer"},"pendientes":{"type":"integer"}},"required":["total","activos","pendientes"],"description":"Números autorizados de la empresa"},"ambiente":{"type":"string","enum":["sandbox","test","cert","prod"],"description":"Ambiente en el que se emite por WhatsApp"}},"required":["modo","habilitado","motivo","plataformaDisponible","configuracion","numeroWhatsapp","enlaceWhatsapp","esSandbox","codigoSandbox","interprete","numeros","ambiente"]},"ModoWhatsappInput":{"type":"object","properties":{"modo":{"type":"string","enum":["firmo","propio"],"description":"firmo = WhatsApp de Firmo (número de la plataforma, por defecto); propio = tu propia cuenta de Twilio"}},"required":["modo"]},"ListaNumerosWhatsapp":{"type":"object","properties":{"numeros":{"type":"array","items":{"$ref":"#/components/schemas/NumeroWhatsapp"}},"usuarios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nombre":{"type":"string"},"correo":{"type":"string"},"rol":{"type":"string"}},"required":["id","nombre","correo","rol"]},"description":"Usuarios activos de la cuenta a quienes se puede asignar un número"},"limite":{"type":"integer"}},"required":["numeros","usuarios","limite"]},"NumeroWhatsapp":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"telefono":{"type":"string","description":"E.164, p. ej. +18095551234"},"etiqueta":{"type":["string","null"]},"usuario":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nombre":{"type":"string"},"correo":{"type":"string"},"rol":{"type":"string"}},"required":["id","nombre","correo","rol"],"description":"Usuario al que pertenece el número: de él salen el rol y los permisos"},"estado":{"type":"string","enum":["pendiente","activo","desactivado"],"description":"pendiente: se activa con el primer mensaje que llegue de ese número"},"verificadoEn":{"type":["string","null"],"description":"Cuándo escribió por primera vez (activación)"},"avisos":{"type":"boolean","description":"Recibe avisos proactivos por WhatsApp (certificado por vencer, e-CF con error, secuencias…). Solo dueño o admin, en el WhatsApp de Firmo."},"ultimoUsoEn":{"type":["string","null"]},"creadoEn":{"type":"string"}},"required":["id","telefono","etiqueta","usuario","estado","verificadoEn","avisos","ultimoUsoEn","creadoEn"]},"AgregarNumeroWhatsappInput":{"type":"object","properties":{"telefono":{"type":"string","minLength":7,"maxLength":30,"example":"809-555-1234","description":"Número de WhatsApp; los de 10 dígitos se toman como +1 (RD, EE. UU., Canadá)"},"usuarioId":{"type":"string","format":"uuid","description":"Usuario de la cuenta al que pertenece el número (define el rol)"},"etiqueta":{"type":"string","maxLength":60,"example":"Caja"}},"required":["telefono","usuarioId"]},"EditarNumeroWhatsappInput":{"type":"object","properties":{"activo":{"type":"boolean","description":"false desactiva el número (deja de atenderse); true lo reactiva"},"etiqueta":{"type":["string","null"],"maxLength":60},"avisos":{"type":"boolean","description":"false deja de enviarle avisos proactivos; true los reactiva"},"usuarioId":{"type":"string","format":"uuid","description":"Reasigna el número a otro usuario de la cuenta"}}},"UsoWhatsapp":{"type":"object","properties":{"aplica":{"type":"boolean","description":"true solo en el WhatsApp de Firmo: con número propio no hay límite ni medidor"},"mes":{"type":"string","description":"YYYY-MM (hora de RD)"},"plan":{"type":"string"},"facturas":{"type":"integer","description":"Facturas emitidas por WhatsApp este mes"},"limite":{"type":["integer","null"],"description":"Facturas por WhatsApp permitidas al mes; null = sin límite"},"origen":{"type":"string","enum":["plan","personalizado","ilimitado"],"description":"De dónde sale el límite: el plan o un ajuste de la administración"},"alcanzado":{"type":"boolean"}},"required":["aplica","mes","plan","facturas","limite","origen","alcanzado"]}},"parameters":{}},"paths":{"/health":{"get":{"tags":["Sistema"],"summary":"Estado del servicio","responses":{"200":{"description":"Servicio operativo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Salud"}}}},"503":{"description":"Base de datos no disponible"}}}},"/v1/accounts":{"post":{"tags":["Cuentas"],"summary":"Registro autoservicio (sandbox)","description":"Crea la cuenta, una empresa de sandbox (con el RNC indicado o uno ficticio), un certificado autofirmado, secuencias de prueba para los 10 tipos de e-CF y una API key `sk_test_`. La llave solo se muestra una vez.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrearCuentaInput"}}}},"responses":{"201":{"description":"Cuenta creada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CuentaCreada"}}}},"400":{"description":"Validación fallida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Ya existe una cuenta con ese correo (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/signup":{"post":{"tags":["Usuarios y sesiones"],"summary":"Crear cuenta con usuario y contraseña","description":"Crea la cuenta, el usuario (rol `dueno`) y la empresa principal en sandbox (con certificado y secuencias de prueba, igual que `/v1/accounts`). Devuelve una sesión `ses_…` válida 30 días.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistroInput"}}}},"responses":{"201":{"description":"Cuenta y sesión creadas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SesionCreada"}}}},"400":{"description":"Validación fallida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Ya existe una cuenta con ese correo (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Demasiados registros desde esta IP","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/login":{"post":{"tags":["Usuarios y sesiones"],"summary":"Iniciar sesión","description":"Responde 401 `credenciales_invalidas` sin revelar si el correo existe. Máximo 10 intentos fallidos cada 15 minutos por correo e IP (429).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginInput"}}}},"responses":{"200":{"description":"Sesión creada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SesionCreada"}}}},"400":{"description":"Validación fallida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Correo o contraseña incorrectos (`credenciales_invalidas`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Demasiados intentos (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/logout":{"post":{"tags":["Usuarios y sesiones"],"summary":"Cerrar la sesión actual","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sesión revocada","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"La solicitud no usa una sesión (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/me":{"get":{"tags":["Usuarios y sesiones"],"summary":"Usuario, cuenta y empresas de la sesión","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Usuario actual","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Yo"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"La solicitud no usa una sesión (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/password/forgot":{"post":{"tags":["Usuarios y sesiones"],"summary":"Pedir un código para recuperar la contraseña","description":"Responde **siempre 202** con el mismo mensaje, exista o no el correo, para no revelar qué cuentas existen. Si existe, envía por correo un código de 6 dígitos que vence a los 15 minutos e invalida los anteriores. Límites: 3 solicitudes por correo cada 15 minutos y 20 por IP por hora; al pasarlos responde igual 202, sin enviar.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OlvidePasswordInput"}}}},"responses":{"202":{"description":"Solicitud recibida","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"mensaje":{"type":"string"}},"required":["ok","mensaje"]}}}},"400":{"description":"Validación fallida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/password/reset":{"post":{"tags":["Usuarios y sesiones"],"summary":"Crear una contraseña nueva con el código","description":"Verifica el código (5 intentos por código; al quinto fallo se invalida), guarda la contraseña nueva (mínimo 10 caracteres), **cierra todas las sesiones** del usuario y devuelve una sesión nueva. Ante cualquier problema con el código responde 400 `codigo_invalido` sin dar más detalles. Envía un correo de aviso.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestablecerPasswordInput"}}}},"responses":{"200":{"description":"Contraseña cambiada y sesión nueva","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SesionCreada"}}}},"400":{"description":"Validación fallida (`validacion`) o código no válido o vencido (`codigo_invalido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/password":{"post":{"tags":["Usuarios y sesiones"],"summary":"Cambiar la contraseña (con sesión)","description":"Verifica la contraseña actual, guarda la nueva (mínimo 10 caracteres) y **cierra las demás sesiones** del usuario; la sesión actual sigue activa. Máximo 5 intentos fallidos cada 15 minutos (429). Envía un correo de aviso.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CambiarPasswordInput"}}}},"responses":{"200":{"description":"Contraseña cambiada","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"sesionesCerradas":{"type":"integer"}},"required":["ok","sesionesCerradas"]}}}},"400":{"description":"Validación fallida o contraseña actual incorrecta (`validacion`, campo `actual`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"La solicitud no usa una sesión (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Demasiados intentos fallidos (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/api-keys":{"get":{"tags":["API keys"],"summary":"Listar API keys de la cuenta","description":"Solo con sesión del portal. Nunca devuelve la llave completa.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Llaves activas","content":{"application/json":{"schema":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResumen"}}},"required":["datos"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["API keys"],"summary":"Crear una API key","description":"`sandbox` crea una `sk_test_`; `prod` una `sk_live_`, que exige la certificación DGII completada (409 `certificacion_pendiente`). La llave se muestra una sola vez.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrearApiKeyInput"}}}},"responses":{"201":{"description":"Llave creada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreada"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La certificación no está completada (`certificacion_pendiente`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/api-keys/{id}":{"delete":{"tags":["API keys"],"summary":"Revocar una API key","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Revocada","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"revocada":{"type":"boolean"}},"required":["id","revocada"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/customers":{"get":{"tags":["Catálogo"],"summary":"Listar clientes","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","maxLength":100,"description":"Busca por nombre o RNC (clientes) o por descripción o código (productos)"},"required":false,"description":"Busca por nombre o RNC (clientes) o por descripción o código (productos)","name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Clientes","content":{"application/json":{"schema":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/Cliente"}}},"required":["datos"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Catálogo"],"summary":"Crear un cliente","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClienteInput"}}}},"responses":{"201":{"description":"Creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cliente"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/customers/{id}":{"patch":{"tags":["Catálogo"],"summary":"Actualizar un cliente","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClienteParcial"}}}},"responses":{"200":{"description":"Actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cliente"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Catálogo"],"summary":"Eliminar un cliente","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Eliminado","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"eliminado":{"type":"boolean"}},"required":["id","eliminado"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/products":{"get":{"tags":["Catálogo"],"summary":"Listar productos y servicios","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","maxLength":100,"description":"Busca por nombre o RNC (clientes) o por descripción o código (productos)"},"required":false,"description":"Busca por nombre o RNC (clientes) o por descripción o código (productos)","name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Productos","content":{"application/json":{"schema":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/Producto"}}},"required":["datos"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Catálogo"],"summary":"Crear un producto o servicio","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductoInput"}}}},"responses":{"201":{"description":"Creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Producto"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/products/{id}":{"patch":{"tags":["Catálogo"],"summary":"Actualizar un producto","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductoParcial"}}}},"responses":{"200":{"description":"Actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Producto"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Catálogo"],"summary":"Eliminar un producto","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Eliminado","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"eliminado":{"type":"boolean"}},"required":["id","eliminado"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/summary":{"get":{"tags":["Empresa"],"summary":"Resumen del mes para el panel","description":"e-CF del mes (hora de RD) por estado, montos e ITBIS de los aceptados, recibidos pendientes de aprobar, secuencias por agotarse, vencimiento del certificado y estado de la certificación.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Resumen","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Resumen"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tools/sign-xml":{"post":{"tags":["Certificación DGII"],"summary":"Firmar un XML con el certificado de la empresa","description":"`multipart/form-data` con `archivo` (.xml), por ejemplo el XML de postulación que se descarga de la DGII. Devuelve el XML firmado (XMLDSig enveloped, RSA-SHA256, como exige la DGII) con el certificado digital real de la empresa.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"archivo":{"type":"string","format":"binary","description":"XML a firmar (máx. 2 MB)"}}}}}},"responses":{"200":{"description":"XML firmado","content":{"application/xml":{"schema":{"type":"string"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"La empresa no tiene su certificado real (`certificado_faltante`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf":{"post":{"tags":["e-CF emitidos"],"summary":"Emitir un e-CF","description":"Valida, asigna el e-NCF (si no se envía), calcula totales y encola el envío a la DGII. Responde **202** con el e-CF en `pendiente`. Con `?wait=true` espera hasta 20 s el resultado final y responde **200** si lo obtiene.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["true","false"],"description":"Esperar el resultado de la DGII (máx. 20 s)"},"required":false,"description":"Esperar el resultado de la DGII (máx. 20 s)","name":"wait","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"},{"schema":{"type":"string","example":"sdk","description":"Valores admitidos: `api`, `sdk`, `mcp`, `sheets`. Canal que declaras para el e-CF que se crea (solo con API key; se guarda en `canal`). Los clientes oficiales lo envían solos (`sdk`, `mcp`, `sheets`). Es información declarada por el cliente, no verificada. Cualquier otro valor se ignora y queda `api`; con sesión del portal se ignora siempre."},"required":false,"description":"Valores admitidos: `api`, `sdk`, `mcp`, `sheets`. Canal que declaras para el e-CF que se crea (solo con API key; se guarda en `canal`). Los clientes oficiales lo envían solos (`sdk`, `mcp`, `sheets`). Es información declarada por el cliente, no verificada. Cualquier otro valor se ignora y queda `api`; con sesión del portal se ignora siempre.","name":"firmo-channel","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitirEcfInput"}}}},"responses":{"200":{"description":"e-CF con resultado final (solo con wait=true)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ecf"}}}},"202":{"description":"e-CF aceptado por Firmo y en cola","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ecf"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`conflicto`, `secuencia_agotada` o `idempotencia`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`certificado_faltante` o `empresa_incompleta`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["e-CF emitidos"],"summary":"Listar e-CF","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["pendiente","en_proceso","aceptado","aceptado_condicional","rechazado","error"],"description":"Estado del e-CF (campo `estado`)"},"required":false,"description":"Estado del e-CF (campo `estado`)","name":"status","in":"query"},{"schema":{"type":"number","description":"Tipo de e-CF (campo `tipo`), p. ej. 31"},"required":false,"description":"Tipo de e-CF (campo `tipo`), p. ej. 31","name":"type","in":"query"},{"schema":{"type":"string","enum":["portal","api","sdk","mcp","sheets","whatsapp","excel","certificacion"],"description":"Canal por el que se creó el e-CF (campo `canal`): portal, api, sdk, mcp, sheets, whatsapp, excel o certificacion"},"required":false,"description":"Canal por el que se creó el e-CF (campo `canal`): portal, api, sdk, mcp, sheets, whatsapp, excel o certificacion","name":"channel","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Fecha de emisión desde (inclusive)"},"required":false,"description":"Fecha de emisión desde (inclusive)","name":"from","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Fecha de emisión hasta (inclusive)"},"required":false,"description":"Fecha de emisión hasta (inclusive)","name":"to","in":"query"},{"schema":{"type":"string","enum":["true","false"],"description":"true: solo los e-CF que requieren atención (campo `requiereAtencion`): `error`, `rechazado` sin corregir, `pendiente` sin avanzar más de 5 min y `en_proceso` de más de 10 min"},"required":false,"description":"true: solo los e-CF que requieren atención (campo `requiereAtencion`): `error`, `rechazado` sin corregir, `pendiente` sin avanzar más de 5 min y `en_proceso` de más de 10 min","name":"needsAction","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Página de e-CF (más recientes primero)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginadoEcf"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}":{"get":{"tags":["e-CF emitidos"],"summary":"Obtener un e-CF","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"e-CF","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ecf"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/input":{"get":{"tags":["e-CF emitidos"],"summary":"Datos con los que se emitió el e-CF","description":"El `EmitirEcfInput` validado con el que se emitió (ítems, comprador, forma de pago…). Sirve para precargar la corrección de un rechazado.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Datos de emisión","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitirEcfInput"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/xml":{"get":{"tags":["e-CF emitidos"],"summary":"XML firmado","description":"XML firmado del e-CF. Para facturas de consumo enviadas como resumen, `?rfce=true` devuelve el RFCE enviado a la DGII.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"rfce","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"XML firmado","content":{"application/xml":{"schema":{"type":"string"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El e-CF aún no está firmado (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/pdf":{"get":{"tags":["e-CF emitidos"],"summary":"Representación impresa","description":"HTML imprimible con el QR de consulta y el código de seguridad, en el formato de la empresa (`/v1/company/invoice-format`). `?paper=` la imprime en otro tamaño; sin él usa el papel de su tipo o el predeterminado. La térmica solo se admite en los tipos 31 y 32.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","enum":["carta","media_carta","termica_80","termica_58"],"description":"`carta`, `media_carta`, `termica_80` o `termica_58`"},"required":false,"description":"`carta`, `media_carta`, `termica_80` o `termica_58`","name":"paper","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Representación impresa","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El e-CF aún no está firmado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/qr":{"get":{"tags":["e-CF emitidos"],"summary":"QR de consulta (PNG)","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"PNG del QR","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El e-CF aún no está firmado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/resend":{"post":{"tags":["e-CF emitidos"],"summary":"Reenviar el mismo XML firmado a la DGII","description":"Solo para e-CF que **no llegaron** a la DGII: estado `error`, o `pendiente` con más de 5 minutos sin avanzar. Antes de reenviar, Firmo consulta a la DGII por si el comprobante ya estaba allí (así no se duplica); si estaba, solo actualiza el estado. Un `rechazado` responde **409**: no se reenvía, hay que corregirlo con `POST /v1/ecf/{id}/correct`. Un `en_proceso` también responde 409: se consulta con `POST /v1/ecf/{id}/check`. Reglas y fuentes en docs/reintentos-dgii.md.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"responses":{"200":{"description":"La DGII ya tenía el comprobante: estado actualizado, no se reenvió","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ecf"}}}},"202":{"description":"Reenvío encolado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ecf"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"No reenviable: `rechazado` (hay que corregir), `en_proceso` (consultar), final o `pendiente` reciente (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/check":{"post":{"tags":["e-CF emitidos"],"summary":"Consultar el estado real del e-CF en la DGII","description":"Consulta a la DGII por TrackId (o por e-NCF si no hay TrackId) y actualiza el e-CF. Sirve para `en_proceso` atascados y para confirmar si un `error` o un `pendiente` llegó a la DGII. Si el estado cambia, se emiten los webhooks `ecf.<estado>` y `ecf.reintentado`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"responses":{"200":{"description":"Resultado de la consulta y e-CF actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultadoConsultaEcf"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`certificado_faltante`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"La DGII no respondió (`dgii_no_disponible`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/correct":{"post":{"tags":["e-CF emitidos"],"summary":"Corregir un e-CF rechazado","description":"Recibe el `EmitirEcfInput` corregido de un e-CF `rechazado` y lo vuelve a emitir. **Regla:** si la DGII indicó que el e-NCF puede reutilizarse (`secuenciaUtilizada = false`: firma, estructura XSD, firmante o e-NCF/RNC inválidos), se reusa el mismo e-NCF (`regla: mismo_encf`, mismo registro); en cualquier otro caso se emite con un **e-NCF nuevo** (`regla: encf_nuevo`) que enlaza al rechazado con `reemplazaA` / `reemplazadoPor`. Un rechazado solo se corrige una vez (después responde 409). Un e-CF aceptado no se corrige así: se usa una nota de crédito o débito. Ver docs/reintentos-dgii.md.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"},{"schema":{"type":"string","example":"sdk","description":"Valores admitidos: `api`, `sdk`, `mcp`, `sheets`. Canal que declaras para el e-CF que se crea (solo con API key; se guarda en `canal`). Los clientes oficiales lo envían solos (`sdk`, `mcp`, `sheets`). Es información declarada por el cliente, no verificada. Cualquier otro valor se ignora y queda `api`; con sesión del portal se ignora siempre."},"required":false,"description":"Valores admitidos: `api`, `sdk`, `mcp`, `sheets`. Canal que declaras para el e-CF que se crea (solo con API key; se guarda en `canal`). Los clientes oficiales lo envían solos (`sdk`, `mcp`, `sheets`). Es información declarada por el cliente, no verificada. Cualquier otro valor se ignora y queda `api`; con sesión del portal se ignora siempre.","name":"firmo-channel","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitirEcfInput"}}}},"responses":{"202":{"description":"Corrección aceptada y en cola","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CorregirEcfResultado"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"No está rechazado o ya fue corregido (`conflicto`), o `secuencia_agotada`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`certificado_faltante` o `empresa_incompleta`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/attempts":{"get":{"tags":["e-CF emitidos"],"summary":"Historial de intentos del e-CF","description":"Línea de tiempo (más antiguo primero) de envíos, reenvíos, consultas y correcciones, con el resultado y los mensajes de la DGII de cada uno.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Intentos","content":{"application/json":{"schema":{"type":"object","properties":{"datos":{"type":"array","items":{"$ref":"#/components/schemas/IntentoEcf"}}},"required":["datos"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/resend-pending":{"post":{"tags":["e-CF emitidos"],"summary":"Reenviar en lote lo pendiente o con error","description":"Reenvía los e-CF de la empresa en estado `error` o `pendiente` con más de 5 minutos sin avanzar, hasta 100 por llamada (los más antiguos primero). Nunca toca `rechazado`, `en_proceso` ni los aceptados. Usa `Idempotency-Key`: repetir la llamada con la misma clave devuelve el mismo resultado sin reenviar de nuevo. Responde el resultado por e-CF.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"responses":{"200":{"description":"Resultado por e-CF","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReenvioLote"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/ecf/{idOEncf}/email":{"post":{"tags":["e-CF emitidos"],"summary":"Enviar la representación impresa por correo","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","minLength":1,"description":"id (UUID) o e-NCF","example":"E310000000001"},"required":true,"description":"id (UUID) o e-NCF","name":"idOEncf","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnviarCorreoInput"}}}},"responses":{"202":{"description":"Correo encolado","content":{"application/json":{"schema":{"type":"object","properties":{"encolado":{"type":"boolean"},"correo":{"type":"string"}},"required":["encolado","correo"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El e-CF aún no está firmado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/template":{"get":{"tags":["Importaciones"],"summary":"Descargar la plantilla de Excel","description":"Por defecto, la plantilla en lote `firmo-plantilla-facturas.xlsx` con las hojas Facturas, Detalle e Instrucciones, listas desplegables y un ejemplo con datos ficticios. Con `?format=invoice`, el formato de factura `firmo-factura.xlsx`: una hoja «Factura» con la distribución de una factura clásica (una factura por hoja; duplica la hoja para varias) y una hoja Instrucciones. El upload de `POST /v1/imports` detecta cuál de los dos formatos subiste.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["batch","invoice"],"default":"batch","description":"`batch` (por defecto): hojas Facturas y Detalle. `invoice`: una factura por hoja."},"required":false,"description":"`batch` (por defecto): hojas Facturas y Detalle. `invoice`: una factura por hoja.","name":"format","in":"query"}],"responses":{"200":{"description":"Plantilla (.xlsx)","content":{"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports":{"post":{"tags":["Importaciones"],"summary":"Subir un Excel o CSV y validarlo (vista previa)","description":"`multipart/form-data` con `archivo`: el .xlsx de la plantilla (hojas **Facturas** y **Detalle**) o un **.csv** de una sola tabla (una fila por ítem con las columnas de la factura repetidas; el tipo del ítem va en `tipo_item`).\n\nFirmo lee y valida **todo** el archivo con las mismas reglas de `POST /v1/ecf` (más referencias repetidas, ítems sin factura, RNC, fechas y `total_esperado`) y responde la vista previa con los errores por hoja, fila y columna. **No emite nada**: para emitir, `POST /v1/imports/{id}/emit`.\n\nLímites: 5 MB y 2,000 facturas por archivo. Un archivo sin la estructura de la plantilla responde 400.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"archivo":{"type":"string","format":"binary","description":"Excel (.xlsx) de la plantilla de Firmo o CSV"}}}}}},"responses":{"201":{"description":"Vista previa (`validado` o `con_errores`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Importacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Importaciones"],"summary":"Listar importaciones","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Importaciones (más recientes primero)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginadoImportacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/{id}":{"get":{"tags":["Importaciones"],"summary":"Obtener una importación (vista previa y progreso)","description":"Mientras está `emitiendo`, `progreso` y `filas[].resultado` muestran el e-NCF, el estado y los mensajes de la DGII de cada factura. Pasa a `completado` cuando todas tienen su resultado final.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Importación","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Importacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/{id}/emit":{"post":{"tags":["Importaciones"],"summary":"Emitir las facturas de una importación validada","description":"Solo si la importación está `validado` (sin errores). Encola la emisión en lote y responde **202** con la importación en `emitiendo`; consulta el progreso con `GET /v1/imports/{id}`.\n\nCada factura se emite con `idExterno = referencia`: una referencia que ya se emitió no se duplica y su fila queda como `ya_emitida`. Repetir esta llamada no vuelve a emitir. Usa `Idempotency-Key`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"responses":{"202":{"description":"Emisión en cola (o ya en curso)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Importacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La importación tiene errores o es de otro ambiente (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/imports/{id}/results":{"get":{"tags":["Importaciones"],"summary":"Descargar el Excel de resultados","description":"La hoja Facturas original (o el CSV) con las columnas `encf`, `estado`, `mensaje` y `pdf` de cada factura. Antes de emitir, marca las filas con errores.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Resultados (.xlsx)","content":{"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/voids":{"post":{"tags":["e-CF emitidos"],"summary":"Anular rangos de e-NCF no usados (ANECF)","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnularInput"}}}},"responses":{"201":{"description":"Anulación enviada a la DGII","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Anulacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`certificado_faltante`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"La DGII no respondió (`dgii_no_disponible`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/received":{"get":{"tags":["Recibidos"],"summary":"Listar e-CF recibidos de proveedores","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["pendiente","aprobado","rechazado"],"description":"Estado de la aprobación comercial (campo `aprobacion`)"},"required":false,"description":"Estado de la aprobación comercial (campo `aprobacion`)","name":"approval","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Recibidos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginadoRecibido"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/received/{id}":{"get":{"tags":["Recibidos"],"summary":"Obtener un recibido","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Recibido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recibido"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/received/{id}/xml":{"get":{"tags":["Recibidos"],"summary":"XML del e-CF recibido","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"XML","content":{"application/xml":{"schema":{"type":"string"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/received/{id}/approval":{"post":{"tags":["Recibidos"],"summary":"Aprobación o rechazo comercial (ACECF)","description":"Construye el ACECF, lo firma con el certificado de la empresa y lo envía a la DGII.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AprobacionInput"}}}},"responses":{"200":{"description":"Aprobación registrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recibido"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Ya se respondió este e-CF","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"La DGII no respondió (`dgii_no_disponible`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/company":{"get":{"tags":["Empresa"],"summary":"Datos del emisor y ambiente","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Empresa activa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Empresa"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Empresa"],"summary":"Actualizar datos del emisor o ambiente","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActualizarEmpresaInput"}}}},"responses":{"200":{"description":"Empresa actualizada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Empresa"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicto (RNC repetido o no modificable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`certificado_faltante` para pasar a test/cert/prod","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/company/certificate":{"post":{"tags":["Empresa"],"summary":"Subir el certificado digital (.p12)","description":"El .p12 y su contraseña se cifran en reposo (AES-256-GCM con llave maestra; KMS en v2) y nunca se devuelven ni se registran.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SubirCertificadoInput"}}}},"responses":{"200":{"description":"Certificado guardado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Empresa"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/companies":{"get":{"tags":["Empresa"],"summary":"Listar las empresas de la cuenta (integradores)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Empresas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginadoEmpresa"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Empresa"],"summary":"Crear una empresa hija (integradores)","description":"La empresa nace en sandbox con certificado autofirmado y secuencias de prueba. Usa su `id` en el header `Firmo-Company`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrearEmpresaInput"}}}},"responses":{"201":{"description":"Empresa creada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Empresa"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"La API key está limitada a una empresa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Ya existe una empresa con ese RNC en la cuenta","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/company/invoice-format":{"get":{"tags":["Empresa"],"summary":"Formato de la factura impresa","description":"Papel, logo, color, pie y columnas de la representación impresa. Sin formato guardado devuelve el predeterminado (carta, verde de la DGII).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Formato vigente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormatoFactura"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Empresa"],"summary":"Guardar el formato de la factura impresa","description":"Reemplaza los campos enviados (los omitidos se conservan). Los datos obligatorios de la DGII no se pueden ocultar con ninguna opción. La térmica (80 o 58 mm) solo se admite en las facturas de crédito fiscal (31) y de consumo (32): si `papel` o `papelPorTipo` pide térmica para otro tipo, responde 400 con el motivo.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActualizarFormatoFactura"}}}},"responses":{"200":{"description":"Formato guardado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormatoFactura"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/company/invoice-format/logo":{"post":{"tags":["Empresa"],"summary":"Subir el logo de la factura","description":"PNG, JPG o SVG de hasta 512 KB (máximo 4000 × 4000 px). El tipo se verifica por el contenido del archivo. El SVG se sanea: se eliminan scripts, manejadores de eventos, imágenes y referencias externas. En el PDF el logo se dibuja si es PNG (8 bits, sin entrelazado) o JPG; un SVG solo sale en la versión HTML.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/SubirLogoInput"}}}},"responses":{"200":{"description":"Formato con el logo nuevo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormatoFactura"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Empresa"],"summary":"Quitar el logo de la factura","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Formato sin logo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormatoFactura"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Empresa"],"summary":"Descargar el logo guardado","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Imagen","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Sin logo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/company/invoice-format/preview":{"get":{"tags":["Empresa"],"summary":"Vista previa de la factura impresa","description":"HTML de una factura de ejemplo (datos ficticios) con los datos de la empresa y el formato guardado. Los parámetros opcionales (`color`, `footer`, `message`, `code`, `unit`, `discount`, `brand`, `logo`) prueban un cambio sin guardarlo.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["carta","media_carta","termica_80","termica_58"],"description":"Papel; sin él, el del tipo o el predeterminado"},"required":false,"description":"Papel; sin él, el del tipo o el predeterminado","name":"paper","in":"query"},{"schema":{"type":"string","enum":["31","32","33","34","41","43","44","45","46","47"],"description":"Tipo de e-CF (31 por defecto)","example":"32"},"required":false,"description":"Tipo de e-CF (31 por defecto)","name":"type","in":"query"},{"schema":{"type":"string"},"required":false,"name":"color","in":"query"},{"schema":{"type":"string"},"required":false,"name":"footer","in":"query"},{"schema":{"type":"string"},"required":false,"name":"message","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"code","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"unit","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"discount","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"brand","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"logo","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"HTML imprimible","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/sequences":{"get":{"tags":["Secuencias"],"summary":"Listar rangos de e-NCF autorizados","description":"Rangos del ambiente efectivo de la llave (sandbox/test con sk_test_, cert/prod con sk_live_).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Secuencias","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginadoSecuencia"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Secuencias"],"summary":"Registrar un rango autorizado por la DGII","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrearSecuenciaInput"}}}},"responses":{"201":{"description":"Secuencia registrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Secuencia"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El rango se solapa con otro existente (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"Listar webhooks","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Webhooks (secreto enmascarado)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginadoWebhook"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Webhooks"],"summary":"Crear un webhook","description":"Entrega: `POST` JSON `{ id, evento, creadoEn, datos }` con `Firmo-Signature: t=<unix>,v1=<hmac_sha256(secreto, t + \".\" + body)>`. Hasta 8 reintentos con backoff exponencial. El `secreto` solo se muestra en esta respuesta.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"},{"schema":{"type":"string","maxLength":255,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h."},"required":false,"description":"Clave única (p. ej. un UUID) para reintentar sin duplicar. Se guarda 24 h.","name":"idempotency-key","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrearWebhookInput"}}}},"responses":{"201":{"description":"Webhook creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/{id}":{"delete":{"tags":["Webhooks"],"summary":"Eliminar un webhook","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Eliminado","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"eliminado":{"type":"boolean"}},"required":["id","eliminado"]}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/lookups/status":{"get":{"tags":["Consultas"],"summary":"Estado de un e-CF en la DGII (también de terceros)","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^E\\d{12}$"},"required":true,"name":"encf","in":"query"},{"schema":{"type":"string","pattern":"^(\\d{9}|\\d{11})$","description":"RNC del emisor del e-CF"},"required":true,"description":"RNC del emisor del e-CF","name":"issuerRnc","in":"query"},{"schema":{"type":"string","pattern":"^(\\d{9}|\\d{11})$","description":"RNC o cédula del comprador"},"required":false,"description":"RNC o cédula del comprador","name":"buyerRnc","in":"query"},{"schema":{"type":"string","minLength":6,"maxLength":6,"description":"Código de seguridad de 6 caracteres impreso en el comprobante"},"required":true,"description":"Código de seguridad de 6 caracteres impreso en el comprobante","name":"securityCode","in":"query"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Estado reportado por la DGII","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EstadoDgii"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"La DGII no respondió","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/lookups/rnc/{rnc}":{"get":{"tags":["Consultas"],"summary":"Contribuyente en el registro público de RNC de la DGII","description":"Datos del archivo público `DGII_RNC.zip` de la DGII, importado a Firmo y refrescado cada semana. Responde 404 si el RNC no está o si el registro aún no se ha importado.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","example":"101010101"},"required":true,"name":"rnc","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Contribuyente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsultaRnc"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"RNC no encontrado (`no_encontrado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/certification":{"get":{"tags":["Certificación DGII"],"summary":"Progreso de la certificación (pasos 0–15)","description":"Estado, instrucciones, artefactos descargables y resultados (con el detalle de cada envío a la DGII) de cada paso del portal CerteCF.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Progreso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgresoCertificacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/certification/start":{"post":{"tags":["Certificación DGII"],"summary":"Paso 0: validar prerrequisitos e iniciar","description":"Revisa los datos de la empresa y el certificado digital real (vigente y del RNC de la empresa o de una cédula autorizada). Si todo está bien, la empresa pasa al ambiente `cert` (CerteCF).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Certificación iniciada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgresoCertificacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La empresa ya está en producción (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`certificado_faltante` o `empresa_incompleta`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/certification/steps/{n}/run":{"post":{"tags":["Certificación DGII"],"summary":"Ejecutar un paso automático (2, 3, 4 o 5)","description":"Pasos 2 y 3: `multipart/form-data` con `archivo` (el .xlsx que descargaste del portal de la DGII). Firmo arma y valida contra el XSD **todos** los XML antes de encolar: si alguno no cumple responde 400 con el detalle y no envía nada (en el portal un rechazo reinicia todos los contadores).\n\nPaso 4: sin archivo; genera la simulación con los datos de la empresa y su catálogo.\n\nPaso 5: regenera las representaciones impresas del paso 4.\n\nResponde 202 con el paso `en_progreso`; consulta `GET /v1/certification` para ver el avance y cada envío.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":["integer","null"],"minimum":0,"maximum":15,"example":2},"required":false,"name":"n","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"requestBody":{"required":false,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"archivo":{"type":"string","format":"binary","description":"Excel (.xlsx) de la DGII; solo pasos 2 y 3"}}}}}},"responses":{"202":{"description":"Trabajo encolado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasoCertificacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Paso bloqueado, en progreso o ya completado (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Falta el certificado real (`certificado_faltante`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/certification/steps/{n}/complete":{"post":{"tags":["Certificación DGII"],"summary":"Marcar como hecho un paso manual o de espera","description":"Pasos 1, 6, 7, 8, 10, 12, 13, 14 y 15. Al completar el 15 la empresa pasa a `prod`: se habilitan las llaves `sk_live_` y la facturación real.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":["integer","null"],"minimum":0,"maximum":15,"example":2},"required":false,"name":"n","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Progreso actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgresoCertificacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Paso no completable o pasos anteriores pendientes (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/certification/steps/{n}/reset":{"post":{"tags":["Certificación DGII"],"summary":"Volver a dejar un paso pendiente","description":"La DGII reinicia todos los contadores del paso ante cualquier rechazo, así que el reintento es completo. Se borran los resultados y artefactos del paso; en la simulación (4) se usan secuencias nuevas.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":["integer","null"],"minimum":0,"maximum":15,"example":2},"required":false,"name":"n","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Progreso actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgresoCertificacion"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El paso está en ejecución o no se puede reiniciar (`conflicto`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/certification/artifacts/{id}":{"get":{"tags":["Certificación DGII"],"summary":"Descargar un artefacto de la certificación","description":"XML íntegro, ZIP de íntegros o representación impresa (HTML imprimible).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","example":"00000000-0000-4000-8000-000000000000"},"required":false,"description":"Integradores: id de la empresa sobre la que se actúa. Sin él, se usa la empresa principal.","name":"firmo-company","in":"header"}],"responses":{"200":{"description":"Archivo","content":{"application/xml":{"schema":{"type":"string"}},"application/zip":{"schema":{"type":"string","format":"binary"}},"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/dgii/{rnc}/fe/autenticacion/api/semilla":{"get":{"tags":["Receptor DGII"],"summary":"Semilla de autenticación","parameters":[{"schema":{"type":"string","pattern":"^(\\d{9}|\\d{11})$","example":"131000000"},"required":true,"name":"rnc","in":"path"}],"responses":{"200":{"description":"SemillaModel","content":{"application/xml":{"schema":{"type":"string"}}}},"404":{"description":"RNC no registrado en Firmo"}}}},"/dgii/{rnc}/fe/autenticacion/api/validacioncertificado":{"post":{"tags":["Receptor DGII"],"summary":"Validar la semilla firmada y emitir token","description":"Recibe la semilla firmada (multipart, campo `xml`, o XML en el cuerpo) y devuelve un token válido 1 hora.","parameters":[{"schema":{"type":"string","pattern":"^(\\d{9}|\\d{11})$","example":"131000000"},"required":true,"name":"rnc","in":"path"}],"responses":{"200":{"description":"Token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenReceptor"}}}},"400":{"description":"XML ausente o inválido"},"401":{"description":"Semilla o certificado inválidos"},"404":{"description":"RNC no registrado en Firmo"}}}},"/dgii/{rnc}/fe/recepcion/api/ecf":{"post":{"tags":["Receptor DGII"],"summary":"Recibir un e-CF de un proveedor","description":"Requiere `Authorization: Bearer <token>`. Responde el ARECF (acuse de recibo) firmado con el certificado del receptor.","parameters":[{"schema":{"type":"string","pattern":"^(\\d{9}|\\d{11})$","example":"131000000"},"required":true,"name":"rnc","in":"path"}],"responses":{"200":{"description":"ARECF firmado","content":{"application/xml":{"schema":{"type":"string"}}}},"400":{"description":"XML ausente"},"401":{"description":"Token inválido"},"404":{"description":"RNC no registrado en Firmo"}}}},"/dgii/{rnc}/fe/aprobacioncomercial/api/ecf":{"post":{"tags":["Receptor DGII"],"summary":"Recibir la aprobación comercial (ACECF) de un comprador","description":"Requiere `Authorization: Bearer <token>`. Registra la aprobación o el rechazo sobre el e-CF emitido.","parameters":[{"schema":{"type":"string","pattern":"^(\\d{9}|\\d{11})$","example":"131000000"},"required":true,"name":"rnc","in":"path"}],"responses":{"200":{"description":"Procesado","content":{"application/json":{"schema":{"type":"object","properties":{"codigo":{"type":"string"},"mensaje":{"type":"array","items":{"type":"string"}}},"required":["codigo","mensaje"]}}}},"400":{"description":"XML ausente"},"401":{"description":"Token inválido"},"404":{"description":"RNC no registrado en Firmo"}}}},"/v1/channels/whatsapp/config":{"get":{"tags":["WhatsApp"],"summary":"Configuración de Twilio de la empresa","description":"La cuenta de Twilio de la empresa activa, sin el Auth Token (solo sus últimos 4 caracteres), con la URL del webhook y las instrucciones para el sandbox y producción. Solo con sesión y rol dueño o admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Configuración de Twilio de la empresa (sin el Auth Token)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["WhatsApp"],"summary":"Conectar o actualizar la cuenta de Twilio","description":"Crea o actualiza la configuración de la empresa activa y la deja activa. Sin `authToken` conserva el anterior. Si cambian las credenciales, el estado vuelve a `sin_probar`: pruébalas con POST /v1/channels/whatsapp/config/test.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuardarConfigWhatsappInput"}}}},"responses":{"200":{"description":"Configuración de Twilio de la empresa (sin el Auth Token)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["WhatsApp"],"summary":"Desconectar la cuenta de Twilio","description":"Desactiva la configuración (el webhook responde 410). Los números autorizados no se tocan. Para reconectar, PUT de nuevo.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Configuración de Twilio de la empresa (sin el Auth Token)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels/whatsapp/config/test":{"post":{"tags":["WhatsApp"],"summary":"Probar la conexión con Twilio","description":"Consulta la cuenta en Twilio (GET /2010-04-01/Accounts/{SID}.json con Basic auth) y guarda el resultado: `conectado`, o `error` con el motivo en español (credenciales no válidas, cuenta suspendida…). Responde 200 también cuando la prueba falla.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Configuración de Twilio de la empresa (sin el Auth Token)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La empresa no tiene configuración activa (`whatsapp_sin_configurar`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels/whatsapp/config/rotate-webhook":{"post":{"tags":["WhatsApp"],"summary":"Generar una URL de webhook nueva","description":"Cambia el `webhookId`. La URL anterior deja de funcionar (404): pega la nueva en Twilio.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Configuración de Twilio de la empresa (sin el Auth Token)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"La empresa no tiene configuración (`whatsapp_sin_configurar`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels/whatsapp":{"get":{"tags":["WhatsApp"],"summary":"Estado del canal de WhatsApp","description":"Modo de la empresa activa (`firmo` o `propio`), si el canal puede atender, el número al que hay que escribir y cuántos números autorizados tiene. Solo con sesión del portal.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Estado del canal de WhatsApp de la empresa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EstadoWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels/whatsapp/mode":{"put":{"tags":["WhatsApp"],"summary":"Elegir el modo: WhatsApp de Firmo o número propio","description":"`firmo` (por defecto): se factura escribiéndole al número de WhatsApp de la plataforma, sin configurar nada. `propio`: se usa la cuenta de Twilio de la empresa (PUT /v1/channels/whatsapp/config). La lista de números autorizados se conserva al cambiar de modo; las facturas por confirmar se descartan. Solo dueño o admin.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModoWhatsappInput"}}}},"responses":{"200":{"description":"Estado del canal de WhatsApp de la empresa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EstadoWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels/whatsapp/numbers":{"get":{"tags":["WhatsApp"],"summary":"Números autorizados a facturar por WhatsApp","description":"Los teléfonos que pueden facturar por WhatsApp a nombre de la empresa activa, cada uno con su usuario, estado y último uso; y los usuarios a quienes se puede asignar un número. Solo dueño o admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Números autorizados de la empresa y usuarios asignables","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListaNumerosWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["WhatsApp"],"summary":"Autorizar un número","description":"Agrega un teléfono a la lista en estado `pendiente`: no se le escribe nada (WhatsApp solo permite escribir primero con plantillas pagadas). Cuando esa persona le escriba al número de WhatsApp de la empresa, queda `activo` y Firmo le da la bienvenida. Único por empresa y teléfono. Solo dueño o admin.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgregarNumeroWhatsappInput"}}}},"responses":{"201":{"description":"Números autorizados de la empresa y usuarios asignables","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListaNumerosWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El número ya está en la lista (`conflicto`) o se alcanzó el límite","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels/whatsapp/numbers/{id}":{"patch":{"tags":["WhatsApp"],"summary":"Editar, desactivar o reactivar un número autorizado","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditarNumeroWhatsappInput"}}}},"responses":{"200":{"description":"Números autorizados de la empresa y usuarios asignables","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListaNumerosWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe ese número en la empresa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["WhatsApp"],"summary":"Quitar un número de la lista","description":"Lo borra de la lista de autorizados: Firmo deja de atenderlo. Las facturas ya emitidas no se tocan.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Números autorizados de la empresa y usuarios asignables","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListaNumerosWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal con rol dueño o admin (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels/whatsapp/usage":{"get":{"tags":["WhatsApp"],"summary":"Uso del mes frente al límite de facturas por WhatsApp del plan","description":"Facturas emitidas por WhatsApp en el mes (hora de RD) y el límite del plan (o el ajuste de la administración). Solo aplica en el WhatsApp de Firmo. Con sesión del portal.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Uso del mes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsoWhatsapp"}}}},"400":{"description":"Validación fallida (`validacion`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key inválida o ausente (`no_autorizado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Requiere sesión del portal (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Límite de uso excedido (`limite_excedido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels/whatsapp/twilio/{webhookId}":{"post":{"tags":["WhatsApp"],"summary":"Webhook de mensajes entrantes de Twilio (empresa o plataforma)","description":"Hay dos clases de URL, ambas con un `webhookId` aleatorio: la de una empresa con su propio número (la da GET /v1/channels/whatsapp/config, `webhookUrl`) y la del WhatsApp de Firmo (la ve el administrador de la plataforma en /v1/admin/whatsapp). Configúrala en Twilio como «When a message comes in» (HTTP POST). Recibe el formulario `application/x-www-form-urlencoded` de Twilio (`From`, `Body`, `MessageSid`, `NumMedia`…) y valida `X-Twilio-Signature` (HMAC-SHA1 de la URL pública exacta + parámetros ordenados) con el Auth Token de la empresa o de la plataforma, según el id. El remitente (`From`) debe ser un número autorizado: en una URL de empresa, de esa empresa; en la de la plataforma, de cualquier empresa en modo `firmo` (si está en varias, se pregunta cuál). Responde 200 con TwiML vacío al instante; la respuesta sale después por la cuenta de Twilio correspondiente.","parameters":[{"schema":{"type":"string","example":"Xb3kZ9qL0pR2sT4uV6wY8a1c"},"required":true,"name":"webhookId","in":"path"}],"responses":{"200":{"description":"Mensaje encolado (TwiML vacío)","content":{"text/xml":{"schema":{"type":"string"}}}},"403":{"description":"Firma de Twilio inválida (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existe un webhook con ese id (`no_encontrado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"La empresa desconectó su Twilio (`no_encontrado`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/public/ecf/{id}/pdf":{"get":{"tags":["Público"],"summary":"PDF de un e-CF con enlace firmado","description":"Representación impresa en PDF, sin API key. El enlace lo genera Firmo (p. ej. al enviar la factura por WhatsApp): `exp` es el vencimiento en segundos Unix (7 días) y `sig` un HMAC-SHA256 del id y `exp`.","parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Vencimiento (segundos Unix)"},"required":false,"description":"Vencimiento (segundos Unix)","name":"exp","in":"query"},{"schema":{"type":"string","description":"Firma del enlace"},"required":false,"description":"Firma del enlace","name":"sig","in":"query"}],"responses":{"200":{"description":"PDF","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Validación","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Enlace inválido o manipulado (`prohibido`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"El e-CF aún no está firmado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"El enlace venció","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{}}