{"openapi":"3.1.0","info":{"title":"dte-sv — API de Facturación Electrónica de El Salvador","version":"2.0.0","summary":"Emití Documentos Tributarios Electrónicos (DTE) firmados ante el Ministerio de Hacienda de El Salvador con una sola llamada REST.","description":"API REST para emitir DTEs (Factura, CCF, Notas de Crédito/Débito, Factura de Exportación),\ninvalidarlos, reportar devoluciones y emitir por lote — todo firmado y transmitido al MH de El Salvador,\nalineado a la **Normativa de Cumplimiento DTE v2.0** (mayo 2026).\n\n**Autenticación:** header `Authorization: Bearer tqo_...` (API key del Consumer).\n\n**Quickstart, ejemplos y hand-off para IA:** https://dte-sv.tequio.work/developers","contact":{"name":"Tequio — dte-sv","url":"https://dte-sv.tequio.work/developers","email":"dte-sv@tequio.work"},"license":{"name":"Términos de servicio","url":"https://dte-sv.tequio.work/terminos"}},"servers":[{"url":"https://dte-sv.tequio.work","description":"Producción (dte-sv.tequio.work)"}],"externalDocs":{"description":"Guía técnica completa para developers","url":"https://dte-sv.tequio.work/developers"},"tags":[{"name":"Emisión","description":"Emitir un DTE por tipo (síncrono)."},{"name":"IA","description":"Emisión en lenguaje natural: mandás el texto de la venta y la IA elige el tipo de DTE, arma el payload, lo valida y (opcionalmente) lo emite."},{"name":"Eventos","description":"Operaciones sobre DTEs ya emitidos: consulta, invalidación, retorno."},{"name":"Lote","description":"Emisión masiva asíncrona (hasta 100 DTEs)."}],"security":[{"bearerAuth":[]}],"paths":{"/api/dte/factura":{"post":{"tags":["Emisión"],"summary":"Emitir Factura (DTE 01)","description":"Venta a consumidor final. `receptor` opcional si la venta es < $25,000 (= `null`); desde $25,000 inclusive requiere identificación. Los precios INCLUYEN IVA.","operationId":"emitFactura","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FacturaRequest"},"examples":{"consumidorFinal":{"summary":"Consumidor final (sin receptor)","value":{"receptor":null,"items":[{"descripcion":"Servicio mensual SaaS","precioUni":9.99,"tipoItem":2}],"condicionOperacion":1,"formaPagoCodigo":"05","notify":["email"]}},"conReceptor":{"summary":"Con receptor identificado","value":{"receptor":{"tipoDocumento":"36","numDocumento":"06140804941020","nombre":"Cliente Ejemplo, S.A. de C.V.","correo":"cliente@ejemplo.com"},"items":[{"descripcion":"Consultoría","precioUni":250,"tipoItem":2}]}}}}}},"responses":{"200":{"description":"DTE PROCESADO por el MH (sello fiscal válido).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"401":{"description":"API key faltante/inválida o Consumer inactivo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Sin suscripción activa (la org del Consumer debe tener un plan vigente para emitir).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"RECHAZADO por el MH, PENDIENTE_CONTINGENCIA, payload inválido (invalid-payload), o DTE construido que no cumple el schema oficial MH (dte-schema-invalid — rechazo local, sin firmar ni transmitir). El cuerpo distingue el caso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"429":{"description":"Rate limit excedido. Header `Retry-After` indica segundos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/ccf":{"post":{"tags":["Emisión"],"summary":"Emitir Comprobante de Crédito Fiscal (DTE 03)","description":"Venta B2B a un contribuyente IVA. `receptor` obligatorio con NIT/NRC/dirección/distrito. Los precios son SIN IVA (se agrega el 13%).","operationId":"emitCcf","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CcfRequest"},"examples":{"b2b":{"summary":"CCF $113 (100 + IVA)","value":{"receptor":{"nit":"05282111241019","nrc":"3523746","nombre":"INGENIO360, S.A.S. DE C.V.","codActividad":"62020","descActividad":"Consultorías informáticas","direccion":{"departamento":"05","municipio":"21","distrito":"14","complemento":"Santa Tecla, La Libertad"},"correo":"facturacion@ingenio360.com"},"items":[{"descripcion":"Servicio de consultoría tecnológica","precioUni":100,"tipoItem":2}],"notify":["email"]}}}}}},"responses":{"200":{"description":"DTE PROCESADO por el MH (sello fiscal válido).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"401":{"description":"API key faltante/inválida o Consumer inactivo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Sin suscripción activa (la org del Consumer debe tener un plan vigente para emitir).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"RECHAZADO por el MH, PENDIENTE_CONTINGENCIA, payload inválido (invalid-payload), o DTE construido que no cumple el schema oficial MH (dte-schema-invalid — rechazo local, sin firmar ni transmitir). El cuerpo distingue el caso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"429":{"description":"Rate limit excedido. Header `Retry-After` indica segundos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/nota-credito":{"post":{"tags":["Emisión"],"summary":"Emitir Nota de Crédito (DTE 05)","description":"Reducción sobre un CCF/CR/FEX previo. `documentoRelacionado` obligatorio (referencia al original).","operationId":"emitNotaCredito","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotaRequest"}}}},"responses":{"200":{"description":"DTE PROCESADO por el MH (sello fiscal válido).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"401":{"description":"API key faltante/inválida o Consumer inactivo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Sin suscripción activa (la org del Consumer debe tener un plan vigente para emitir).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"RECHAZADO por el MH, PENDIENTE_CONTINGENCIA, payload inválido (invalid-payload), o DTE construido que no cumple el schema oficial MH (dte-schema-invalid — rechazo local, sin firmar ni transmitir). El cuerpo distingue el caso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"429":{"description":"Rate limit excedido. Header `Retry-After` indica segundos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/nota-debito":{"post":{"tags":["Emisión"],"summary":"Emitir Nota de Débito (DTE 06)","description":"Cargo adicional sobre un CCF previo. Mismo schema que Nota de Crédito.","operationId":"emitNotaDebito","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotaRequest"}}}},"responses":{"200":{"description":"DTE PROCESADO por el MH (sello fiscal válido).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"401":{"description":"API key faltante/inválida o Consumer inactivo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Sin suscripción activa (la org del Consumer debe tener un plan vigente para emitir).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"RECHAZADO por el MH, PENDIENTE_CONTINGENCIA, payload inválido (invalid-payload), o DTE construido que no cumple el schema oficial MH (dte-schema-invalid — rechazo local, sin firmar ni transmitir). El cuerpo distingue el caso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"429":{"description":"Rate limit excedido. Header `Retry-After` indica segundos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/factura-exportacion":{"post":{"tags":["Emisión"],"summary":"Emitir Factura de Exportación (DTE 11)","description":"Venta a receptor extranjero. Sin IVA (0%). `codPais` en ISO 3166-1 alpha-2 (`US`, `CR`, `ES`). `receptor.descActividad` es REQUIRED (5-150 chars).","operationId":"emitFacturaExportacion","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportacionRequest"},"examples":{"exportUsa":{"summary":"Exportación a USA","value":{"receptor":{"nombre":"Foreign Buyer LLC","tipoDocumento":"36","numDocumento":"98-7654321","codPais":"US","complemento":"123 Main St, Miami, FL","tipoPersona":2,"descActividad":"Importadora de software"},"items":[{"descripcion":"Licencia de software (export)","precioUni":500,"tipoItem":2}],"tipoMoneda":"USD","codIncoterms":"01","observaciones":"Contrato 2026-014, entrega fase 2 de 3"}}}}}},"responses":{"200":{"description":"DTE PROCESADO por el MH (sello fiscal válido).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"401":{"description":"API key faltante/inválida o Consumer inactivo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Sin suscripción activa (la org del Consumer debe tener un plan vigente para emitir).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"RECHAZADO por el MH, PENDIENTE_CONTINGENCIA, payload inválido (invalid-payload), o DTE construido que no cumple el schema oficial MH (dte-schema-invalid — rechazo local, sin firmar ni transmitir). El cuerpo distingue el caso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"429":{"description":"Rate limit excedido. Header `Retry-After` indica segundos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/ai":{"post":{"tags":["IA"],"summary":"Emitir con IA (lenguaje natural)","description":"Mandás la venta tal como se la contarías a alguien (`input`) y el flujo de IA\n(Generador → validación determinística contra el esquema oficial del MH → Revisor)\nelige el tipo de DTE, arma el payload y decide una `accion`:\n\n- `EMITIR`: el payload está completo y validado. Con `autoEmit: true` (default) se\n  transmite a Hacienda en la misma llamada y `dte` trae el resultado sellado.\n  Con `autoEmit: false` el flujo corre COMPLETO (incluido el Revisor) pero NO se\n  transmite: usá `payload` para emitirlo por el endpoint manual del tipo, o repetí\n  con `autoEmit: true`.\n- `CONFIRMAR`: falta un dato duro o hay una bifurcación abierta — `datoQueFalta` y\n  `observaciones` dicen qué confirmar. La IA NUNCA inventa datos (NIT, direcciones…).\n- `NO_EMITIR`: la operación no amerita DTE.\n\n**Precio:** $0.02 por petición, se liquida a fin de mes junto al uso del plan.\nSe cobra por PETICIÓN, sin importar la `accion`, en qué etapa quedó el flujo o si\nMH falló. El DTE emitido cuenta ADEMÁS como un DTE normal del plan. Disponible en\ncualquier issuer con plan activo, sin opt-in.\n\n**Rate limit:** bucket propio, separado de la emisión manual, con el mismo límite\npor minuto del Consumer (default 60/min). El DTE que la IA emite NO consume el\nbucket manual.","operationId":"emitConIa","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiEmitRequest"},"examples":{"autoEmit":{"summary":"Emisión directa (autoEmit default true)","value":{"input":"Vendí una lámpara en $100 pero le di $15 de descuento, en efectivo.","ambiente":"01","notify":["email"]}},"revisarPrimero":{"summary":"Armar y validar sin emitir (autoEmit false)","value":{"input":"Le vendí al crédito a 30 días a Ferretería El Constructor S.A. de C.V., NIT 0614-280590-102-1, NRC 240518, giro venta al por mayor de materiales de construcción, dirección Boulevard Constitución #45, distrito de San Salvador, departamento de San Salvador: 50 bolsas de cemento a $8.75 cada una con $25 de descuento en el cemento, y 200 metros de hierro de 3/8 a $1.20 el metro, más IVA. Quedó en $652.50 más IVA.","ambiente":"01","autoEmit":false}}}}}},"responses":{"200":{"description":"El flujo respondió. Sin emisión (accion CONFIRMAR/NO_EMITIR, o autoEmit false): siempre 200. Con emisión: 200 solo si el MH dijo PROCESADO.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiEmitResponse"}}}},"401":{"description":"API key faltante/inválida o Consumer inactivo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Sin plan/suscripción activa en el issuer: la IA está disponible solo con billing al día.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Emisión no PROCESADA (RECHAZADO o PENDIENTE_CONTINGENCIA — cuerpo AiEmitResponse con `dte`), o errores de request: payload inválido / ambiente no configurado (cuerpo ErrorResponse).","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AiEmitResponse"},{"$ref":"#/components/schemas/ErrorResponse"}]}}}},"429":{"description":"Rate limit del bucket IA excedido. Header `Retry-After` indica segundos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"502":{"description":"Motor de IA no disponible (ai-unavailable). La petición igual se contabiliza ($0.02).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"No se pudo registrar el uso (ai-metering-unavailable). La petición NO se cobró — reintentá en unos segundos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/{codigoGeneracion}":{"get":{"tags":["Eventos"],"summary":"Consultar estado de un DTE","description":"Estado y assets de un DTE emitido por tu Consumer.","operationId":"getDte","security":[{"bearerAuth":[]}],"parameters":[{"name":"codigoGeneracion","in":"path","required":true,"schema":{"type":"string"},"description":"UUID v4 MAYÚSCULAS."}],"responses":{"200":{"description":"Estado + assets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmitResponse"}}}},"404":{"description":"No existe o no pertenece a tu Consumer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/{codigoGeneracion}/invalidar":{"post":{"tags":["Eventos"],"summary":"Invalidar un DTE (Normativa v2 §13.1)","description":"Invalida un DTE PROCESADO (tipos 01, 03, 11). Plazos por `tipoInvalidacion`: 1=error (10 primeros días hábiles del mes siguiente), 2=rescisión (3 meses), 3=medicamentos (2 años). Pasado el plazo, usá Nota de Crédito.","operationId":"invalidarDte","security":[{"bearerAuth":[]}],"parameters":[{"name":"codigoGeneracion","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvalidarRequest"}}}},"responses":{"200":{"description":"Invalidación procesada por el MH.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Plazo vencido / payload inválido / MH rechazó.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/{codigoGeneracion}/retorno":{"post":{"tags":["Eventos"],"summary":"Reportar devolución (Retorno, Normativa v2 §13.3)","description":"Devolución parcial o total sobre un DTE B2C (01, 11, 14) SIN invalidarlo. Plazo: 3 meses desde el sello. Para CCF usá Nota de Crédito.","operationId":"retornoDte","security":[{"bearerAuth":[]}],"parameters":[{"name":"codigoGeneracion","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetornoRequest"}}}},"responses":{"200":{"description":"Retorno procesado.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Plazo vencido / inválido / MH rechazó.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/retorno/{codigoGeneracion}/invalidar":{"post":{"tags":["Eventos"],"summary":"Invalidar un Evento de Retorno (Normativa v2 §13.1 Cuadro 6 fila 4)","description":"Invalida un EVENTO DE RETORNO sellado (errores en su contenido — el retorno no es ajustable, §13.3.2.1). `codigoGeneracion` es el del EVENTO (el que devolvió POST /api/dte/{codGen}/retorno), no el del DTE original. Plazo: 10 primeros días hábiles del mes siguiente al sello del evento. El DTE original no se ve afectado.","operationId":"invalidarRetorno","security":[{"bearerAuth":[]}],"parameters":[{"name":"codigoGeneracion","in":"path","required":true,"schema":{"type":"string"},"description":"codigoGeneracion del Evento de Retorno."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvalidarEventoRequest"}}}},"responses":{"200":{"description":"Invalidación del evento procesada por el MH.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Plazo vencido / evento sin sello / MH rechazó.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/lote":{"post":{"tags":["Lote"],"summary":"Emisión por lote (hasta 100 DTEs)","description":"Asíncrono — devuelve `codigoLote` para poll. Restringido por horario (prod 22:00-05:00 SV; pruebas 08:00-17:00). Para contingencia 24/7 pasá `contingencia: true`.","operationId":"emitLote","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoteRequest"}}}},"responses":{"200":{"description":"Lote recibido.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoteResponse"}}}},"422":{"description":"Fuera de ventana horaria / inválido.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/dte/lote/{codigoLote}":{"get":{"tags":["Lote"],"summary":"Consultar resultado de un lote","description":"Idempotente. Actualiza los DTEs locales a PROCESADO/RECHAZADO según el lote termine.","operationId":"getLote","security":[{"bearerAuth":[]}],"parameters":[{"name":"codigoLote","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Estado del lote.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"tqo_…","description":"API key del Consumer (`tqo_...`). Se entrega una sola vez al registrarte."}},"schemas":{"Direccion":{"type":"object","required":["departamento","municipio","distrito","complemento"],"properties":{"departamento":{"type":"string","description":"CAT-012, 2 dígitos.","example":"06"},"municipio":{"type":"string","description":"CAT-013, 2 dígitos.","example":"21"},"distrito":{"type":"string","description":"CAT-008 (NUEVO en Normativa v2), 2 dígitos.","example":"02"},"complemento":{"type":"string","maxLength":200,"example":"Calle La Reforma #123, San Salvador"}}},"Item":{"type":"object","required":["descripcion","precioUni"],"properties":{"descripcion":{"type":"string","example":"Servicio mensual SaaS"},"cantidad":{"type":"number","default":1,"example":1},"precioUni":{"type":"number","description":"Para Factura (01) INCLUYE IVA; para CCF/NC/ND es el neto (el IVA se agrega).","example":9.99},"uniMedida":{"type":"integer","description":"CAT-014. Default 59 (unidad).","default":59},"tipoItem":{"type":"integer","enum":[1,2,3,4],"description":"1=bien, 2=servicio, 3=ambos, 4=otros.","default":2},"codigo":{"type":"string","maxLength":25,"description":"Tu SKU interno (opcional)."}}},"ReceptorFactura":{"type":["object","null"],"description":"Opcional para ventas < $25,000 (consumidor final = `null`). Desde $25,000 inclusive (>= $25,000) requiere identificación: nombre + tipoDocumento + numDocumento.","required":["tipoDocumento","numDocumento","nombre"],"properties":{"tipoDocumento":{"type":"string","enum":["13","36","37","02","03"],"description":"CAT-022. 13=DUI, 36=NIT, 37=Otro, 02=Carnet residente, 03=Pasaporte."},"numDocumento":{"type":"string","description":"Con guion para DUI: 01234567-8."},"nombre":{"type":"string"},"nrc":{"type":"string"},"codActividad":{"type":"string"},"descActividad":{"type":"string"},"direccion":{"$ref":"#/components/schemas/Direccion"},"telefono":{"type":"string","description":"8 dígitos para El Salvador (con o sin separadores: 7600-3452, 7600 3452) o formato internacional con prefijo + para otros países (+504 7660-4544). Se guarda sin separadores en el DTE. Si pedís entrega por WhatsApp, se interpreta a E.164 (default SV); si no se reconoce un número válido, ese canal se omite sin bloquear la emisión.","example":"7600-3452"},"correo":{"type":"string","format":"email","description":"Si pedís entrega por correo y va vacío o inválido, ese canal se omite sin bloquear la emisión."}}},"ReceptorCcf":{"type":"object","description":"Obligatorio. El receptor debe estar inscrito en IVA.","required":["nit","nrc","nombre","codActividad","descActividad","direccion"],"properties":{"nit":{"type":"string","description":"14 dígitos.","example":"05282111241019"},"nrc":{"type":"string","description":"1-8 dígitos.","example":"3523746"},"nombre":{"type":"string","example":"INGENIO360, S.A.S. DE C.V."},"codActividad":{"type":"string","description":"CAT-019, 5-6 dígitos.","example":"62020"},"descActividad":{"type":"string","example":"Consultorías informáticas"},"nombreComercial":{"type":"string"},"direccion":{"$ref":"#/components/schemas/Direccion"},"telefono":{"type":"string","description":"8 dígitos para El Salvador (con o sin separadores: 7600-3452, 7600 3452) o formato internacional con prefijo + para otros países (+504 7660-4544). Se guarda sin separadores en el DTE. Si pedís entrega por WhatsApp, se interpreta a E.164 (default SV); si no se reconoce un número válido, ese canal se omite sin bloquear la emisión.","example":"7600-3452"},"correo":{"type":"string","format":"email","description":"Si pedís entrega por correo y va vacío o inválido, ese canal se omite sin bloquear la emisión."}}},"DocumentoRelacionado":{"type":"object","required":["tipoDocumento","numeroDocumento","fechaEmision"],"properties":{"tipoDocumento":{"type":"string","enum":["03","07","11"],"description":"Tipo del documento original (03=CCF, 07=Retención, 11=FEX)."},"tipoGeneracion":{"type":"integer","enum":[1,2],"default":2,"description":"2=electrónico."},"numeroDocumento":{"type":"string","description":"codigoGeneracion del DTE original (UUID v4 MAYÚSCULAS)."},"fechaEmision":{"type":"string","format":"date","description":"YYYY-MM-DD del DTE original."}}},"Persona":{"type":"object","required":["nombre","tipoDocumento","numDocumento"],"properties":{"nombre":{"type":"string"},"tipoDocumento":{"type":"string","enum":["13","36","37","02","03"]},"numDocumento":{"type":"string"}}},"Assets":{"type":"object","properties":{"portalUrl":{"type":"string","format":"uri","description":"Portal público del DTE (descarga PDF + Archivo DTE)."},"pdfUrl":{"type":"string","format":"uri","description":"Representación gráfica (PDF). URL firmada, válida 30 días."},"jwsUrl":{"type":"string","format":"uri","description":"JWS firmado (auditoría)."},"jsonUrl":{"type":"string","format":"uri","description":"JSON canónico del DTE."}}},"EmitResponse":{"type":"object","properties":{"dteId":{"type":"string","format":"uuid"},"codigoGeneracion":{"type":"string","description":"UUID v4 MAYÚSCULAS — identificador del DTE ante el MH."},"numeroControl":{"type":"string","example":"DTE-01-M001P001-000000000000186"},"estado":{"type":"string","enum":["PROCESADO","RECHAZADO","PENDIENTE_CONTINGENCIA"]},"selloRecibido":{"type":["string","null"],"description":"Sello fiscal del MH. null si RECHAZADO o en contingencia."},"fhProcesamiento":{"type":["string","null"],"description":"Fecha/hora de procesamiento MH (DD/MM/YYYY HH:mm:ss)."},"mhResponse":{"type":"object","additionalProperties":true,"description":"Respuesta cruda del MH."},"jws":{"type":"string","description":"DTE firmado (JWS RS512)."},"assets":{"$ref":"#/components/schemas/Assets"},"notifications":{"type":"object","additionalProperties":true,"description":"Resultado de las notificaciones pedidas en `notify`."},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}},"ErrorResponse":{"type":"object","properties":{"error":{"oneOf":[{"type":"string","description":"Código de error (capa de billing/validación)."},{"type":"object","properties":{"reason":{"type":"string"},"message":{"type":"string"}}}]},"message":{"type":"string","description":"Mensaje legible. Para `dte-schema-invalid` lidera con los `friendlyIssues` (el campo, el porqué y el valor, en español) — el rechazo es local, contra el esquema oficial del MH, sin firmar ni transmitir."},"friendlyIssues":{"type":"array","items":{"type":"string"},"description":"Solo en `dte-schema-invalid`: errores del esquema oficial MH traducidos a español accionable, nombrando el campo (label oficial + path JSON como `receptor.descActividad`), el límite y el valor ofensor. Máx 8."},"issues":{"type":"array","items":{"oneOf":[{"type":"object","additionalProperties":true},{"type":"string"}]},"description":"Detalle CRUDO de validación: issues de zod (error=invalid-payload) o errores del schema oficial MH formateados `path mensaje`, máx 5 (error=dte-schema-invalid; `totalIssues` trae el total). Para texto legible usar `friendlyIssues`."}}},"FacturaRequest":{"type":"object","required":["items"],"properties":{"ambiente":{"type":"string","enum":["00","01"],"description":"Ambiente donde emitir. **Obligatorio** — no hay default, hay que enviarlo siempre (incluso si el Issuer tiene un solo ambiente configurado). 00=pruebas, 01=producción. Pedir uno no configurado devuelve 422 `ambiente-not-configured` con la lista `available`."},"issuerId":{"type":"string","description":"UUID del Issuer. Default = primero en allowedIssuerIds del Consumer."},"codActividad":{"type":"string","description":"Actividad económica (CAT-019) del EMISOR bajo la cual emitir. Debe ser una de las registradas en el Issuer; si se omite, usa la principal. Una no registrada devuelve 400 `actividad-not-allowed`."},"items":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/Item"}},"condicionOperacion":{"type":"integer","enum":[1,2,3],"description":"1=contado, 2=crédito, 3=otro.","default":1},"formaPagoCodigo":{"type":"string","description":"CAT-017. 01=billetes, 02=tarjeta débito, 03=tarjeta crédito, 05=transferencia.","default":"01"},"notify":{"type":"array","items":{"type":"string","enum":["email","whatsapp"]},"description":"Canales por los que dte-sv notifica al receptor tras emitir. Solo se procesan los que el Issuer habilita."},"notifyOnContingencyResolution":{"type":"boolean","default":true,"description":"Si el DTE entra en contingencia, ¿re-notificar al receptor cuando se resuelva? Solo se respeta `false` para 01/11/14/15."},"fechaEmision":{"type":"string","description":"Fecha-hora de generación (fecEmi/horEmi) del DTE, en hora El Salvador (UTC-6). OPCIONAL: si se omite se usa el momento actual (default). Si se envía, se valida contra las cotas del MH y se rechaza con 422 `fecha-emision-invalida` (sin ir al MH) si las infringe: retro-fechar es libre hasta 2000-01-01 (Normativa Identificación campo 10.2 — «cualquier fecha que anteceda»); post-fechar hasta 5 días sin cruzar al siguiente período tributario mensual (campo 10.4). Formato: `YYYY-MM-DD`, `YYYY-MM-DDTHH:mm[:ss]` (hora SV) o ISO 8601 con offset."},"receptor":{"$ref":"#/components/schemas/ReceptorFactura"}}},"AiEmitRequest":{"type":"object","required":["input","ambiente"],"properties":{"input":{"type":"string","minLength":1,"maxLength":8500,"description":"La venta/operación en lenguaje natural, como se la contarías a alguien. Incluí TODO lo que tengas (receptor, NIT/NRC, giro, dirección, montos, forma de pago): lo que falte, la IA lo pregunta en vez de inventarlo. Límite real: 8500 bytes UTF-8 (las tildes cuentan 2 bytes; los emojis se descartan antes de procesar). Debe contener al menos 4 caracteres alfanuméricos una vez descartados los emojis: un texto que no describe una operación (vacío, solo emojis o solo signos) se rechaza con 422 `invalid-payload` antes de llegar a la IA y sin cobrar la petición."},"ambiente":{"type":"string","enum":["00","01"],"description":"\"00\" pruebas · \"01\" producción."},"issuerId":{"type":"string","description":"Emisor a usar. Default: el primero del ACL del Consumer."},"autoEmit":{"type":"boolean","default":true,"description":"true: si la accion final es EMITIR, se transmite a Hacienda en esta misma llamada. false: el flujo corre completo (incluido el Revisor) pero NUNCA transmite — el resultado vuelve para que decidas."},"codActividad":{"type":"string","description":"Actividad económica (CAT-019) del emisor bajo la cual emitir. Default: la principal."},"notify":{"type":"array","items":{"type":"string","enum":["email","whatsapp"]},"description":"Canales de entrega al receptor si el DTE se emite."},"notifyOnContingencyResolution":{"type":"boolean","default":true}}},"AiEmitResponse":{"type":"object","description":"Resultado del flujo de IA. `accion` manda: EMITIR (payload completo y validado), CONFIRMAR (falta un dato — ver datoQueFalta/observaciones) o NO_EMITIR. Si hubo emisión, `dte` trae el mismo cuerpo que los endpoints manuales.","properties":{"id":{"type":"string","description":"Id de la petición de IA (auditoría/correlación)."},"accion":{"type":"string","enum":["EMITIR","CONFIRMAR","NO_EMITIR"]},"tipoDte":{"type":"string","description":"Código del tipo elegido (\"01\", \"03\", …) o \"NONE\"."},"resumenHumano":{"type":["string","null"],"description":"UNA frase con el qué (documento, a quién, monto)."},"observaciones":{"type":"array","items":{"type":"string"},"description":"Supuestos hechos y datos faltantes/dudosos de ESTE DTE."},"consejos":{"type":"array","items":{"type":"string"},"description":"Acciones a futuro para otras operaciones."},"datoQueFalta":{"type":"array","items":{"type":"string"},"description":"Solo con accion CONFIRMAR: claves de lo que falta (RECEPTOR_NIT, RECEPTOR_DIRECCION, RECEPTOR_GIRO, DOC_RELACIONADO_UUID, OTRO…)."},"totalDeclarado":{"type":["number","null"],"description":"Lo que el usuario dijo/implicó que cobró, tal cual."},"fechaEmision":{"type":["string","null"],"description":"Fecha-hora de generación (fecEmi/horEmi, hora El Salvador) detectada del mensaje cuando el usuario la menciona (\"ayer\", \"el 11 de junio a las 7pm\", \"el martes pasado\", \"hace 3 días\"). null = se usó el momento de emisión. La resuelve un parser DETERMINÍSTICO (no el LLM — incluye días de la semana) y se valida igual que en los endpoints manuales; si cae fuera de la ventana del MH, no se emite (422 `fecha-emision-invalida`)."},"payload":{"type":["object","null"],"additionalProperties":true,"description":"Input del builder del tipo elegido — listo para POST /api/dte/<tipo> si preferís emitirlo manualmente tras revisar."},"autoEmit":{"type":"boolean"},"emitido":{"type":"boolean","description":"true = se transmitió a MH y el Dte existe (ver dte.estado: PROCESADO, RECHAZADO o PENDIENTE_CONTINGENCIA)."},"dte":{"oneOf":[{"$ref":"#/components/schemas/EmitResponse"},{"type":"null"}]},"emitError":{"type":"object","additionalProperties":true,"description":"Presente solo si la emisión falló sin transmitir (build-failed, dte-schema-invalid, pipeline-failed)."},"warnings":{"type":"array","items":{"type":"object","additionalProperties":true}},"ruta":{"type":"string","description":"Ruta terminal del flujo (emitir, emitir-corregido, confirmar-api, confirmar-math, flip-placeholder, confirmar-revisor, no-emitir…)."},"ms":{"type":"integer","description":"Duración total de la petición."}}},"CcfRequest":{"type":"object","required":["items","receptor"],"properties":{"ambiente":{"type":"string","enum":["00","01"],"description":"Ambiente donde emitir. **Obligatorio** — no hay default, hay que enviarlo siempre (incluso si el Issuer tiene un solo ambiente configurado). 00=pruebas, 01=producción. Pedir uno no configurado devuelve 422 `ambiente-not-configured` con la lista `available`."},"issuerId":{"type":"string","description":"UUID del Issuer. Default = primero en allowedIssuerIds del Consumer."},"codActividad":{"type":"string","description":"Actividad económica (CAT-019) del EMISOR bajo la cual emitir. Debe ser una de las registradas en el Issuer; si se omite, usa la principal. Una no registrada devuelve 400 `actividad-not-allowed`."},"items":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/Item"}},"condicionOperacion":{"type":"integer","enum":[1,2,3],"description":"1=contado, 2=crédito, 3=otro.","default":1},"formaPagoCodigo":{"type":"string","description":"CAT-017. 01=billetes, 02=tarjeta débito, 03=tarjeta crédito, 05=transferencia.","default":"01"},"notify":{"type":"array","items":{"type":"string","enum":["email","whatsapp"]},"description":"Canales por los que dte-sv notifica al receptor tras emitir. Solo se procesan los que el Issuer habilita."},"notifyOnContingencyResolution":{"type":"boolean","default":true,"description":"Si el DTE entra en contingencia, ¿re-notificar al receptor cuando se resuelva? Solo se respeta `false` para 01/11/14/15."},"fechaEmision":{"type":"string","description":"Fecha-hora de generación (fecEmi/horEmi) del DTE, en hora El Salvador (UTC-6). OPCIONAL: si se omite se usa el momento actual (default). Si se envía, se valida contra las cotas del MH y se rechaza con 422 `fecha-emision-invalida` (sin ir al MH) si las infringe: retro-fechar es libre hasta 2000-01-01 (Normativa Identificación campo 10.2 — «cualquier fecha que anteceda»); post-fechar hasta 5 días sin cruzar al siguiente período tributario mensual (campo 10.4). Formato: `YYYY-MM-DD`, `YYYY-MM-DDTHH:mm[:ss]` (hora SV) o ISO 8601 con offset."},"receptor":{"$ref":"#/components/schemas/ReceptorCcf"}}},"NotaRequest":{"type":"object","required":["items","receptor","documentoRelacionado"],"properties":{"ambiente":{"type":"string","enum":["00","01"],"description":"Ambiente donde emitir. **Obligatorio** — no hay default, hay que enviarlo siempre (incluso si el Issuer tiene un solo ambiente configurado). 00=pruebas, 01=producción. Pedir uno no configurado devuelve 422 `ambiente-not-configured` con la lista `available`."},"issuerId":{"type":"string","description":"UUID del Issuer. Default = primero en allowedIssuerIds del Consumer."},"codActividad":{"type":"string","description":"Actividad económica (CAT-019) del EMISOR bajo la cual emitir. Debe ser una de las registradas en el Issuer; si se omite, usa la principal. Una no registrada devuelve 400 `actividad-not-allowed`."},"items":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/Item"}},"condicionOperacion":{"type":"integer","enum":[1,2,3],"description":"1=contado, 2=crédito, 3=otro.","default":1},"formaPagoCodigo":{"type":"string","description":"CAT-017. 01=billetes, 02=tarjeta débito, 03=tarjeta crédito, 05=transferencia.","default":"01"},"notify":{"type":"array","items":{"type":"string","enum":["email","whatsapp"]},"description":"Canales por los que dte-sv notifica al receptor tras emitir. Solo se procesan los que el Issuer habilita."},"notifyOnContingencyResolution":{"type":"boolean","default":true,"description":"Si el DTE entra en contingencia, ¿re-notificar al receptor cuando se resuelva? Solo se respeta `false` para 01/11/14/15."},"fechaEmision":{"type":"string","description":"Fecha-hora de generación (fecEmi/horEmi) del DTE, en hora El Salvador (UTC-6). OPCIONAL: si se omite se usa el momento actual (default). Si se envía, se valida contra las cotas del MH y se rechaza con 422 `fecha-emision-invalida` (sin ir al MH) si las infringe: retro-fechar es libre hasta 2000-01-01 (Normativa Identificación campo 10.2 — «cualquier fecha que anteceda»); post-fechar hasta 5 días sin cruzar al siguiente período tributario mensual (campo 10.4). Formato: `YYYY-MM-DD`, `YYYY-MM-DDTHH:mm[:ss]` (hora SV) o ISO 8601 con offset."},"receptor":{"$ref":"#/components/schemas/ReceptorCcf"},"documentoRelacionado":{"$ref":"#/components/schemas/DocumentoRelacionado"}}},"ExportacionRequest":{"type":"object","required":["items","receptor"],"properties":{"ambiente":{"type":"string","enum":["00","01"],"description":"Ambiente donde emitir. **Obligatorio** — no hay default, hay que enviarlo siempre (incluso si el Issuer tiene un solo ambiente configurado). 00=pruebas, 01=producción. Pedir uno no configurado devuelve 422 `ambiente-not-configured` con la lista `available`."},"issuerId":{"type":"string","description":"UUID del Issuer. Default = primero en allowedIssuerIds del Consumer."},"codActividad":{"type":"string","description":"Actividad económica (CAT-019) del EMISOR bajo la cual emitir. Debe ser una de las registradas en el Issuer; si se omite, usa la principal. Una no registrada devuelve 400 `actividad-not-allowed`."},"items":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/Item"}},"condicionOperacion":{"type":"integer","enum":[1,2,3],"description":"1=contado, 2=crédito, 3=otro.","default":1},"formaPagoCodigo":{"type":"string","description":"CAT-017. 01=billetes, 02=tarjeta débito, 03=tarjeta crédito, 05=transferencia.","default":"01"},"notify":{"type":"array","items":{"type":"string","enum":["email","whatsapp"]},"description":"Canales por los que dte-sv notifica al receptor tras emitir. Solo se procesan los que el Issuer habilita."},"notifyOnContingencyResolution":{"type":"boolean","default":true,"description":"Si el DTE entra en contingencia, ¿re-notificar al receptor cuando se resuelva? Solo se respeta `false` para 01/11/14/15."},"fechaEmision":{"type":"string","description":"Fecha-hora de generación (fecEmi/horEmi) del DTE, en hora El Salvador (UTC-6). OPCIONAL: si se omite se usa el momento actual (default). Si se envía, se valida contra las cotas del MH y se rechaza con 422 `fecha-emision-invalida` (sin ir al MH) si las infringe: retro-fechar es libre hasta 2000-01-01 (Normativa Identificación campo 10.2 — «cualquier fecha que anteceda»); post-fechar hasta 5 días sin cruzar al siguiente período tributario mensual (campo 10.4). Formato: `YYYY-MM-DD`, `YYYY-MM-DDTHH:mm[:ss]` (hora SV) o ISO 8601 con offset."},"receptor":{"type":"object","required":["nombre","numDocumento","codPais","complemento","descActividad"],"properties":{"nombre":{"type":"string"},"tipoDocumento":{"type":"string","enum":["03","13","36","37"],"default":"03"},"numDocumento":{"type":"string"},"codPais":{"type":"string","description":"CAT-020: ISO 3166-1 alpha-2.","example":"US"},"nombrePais":{"type":"string","default":"EXTRANJERO"},"complemento":{"type":"string"},"tipoPersona":{"type":"integer","enum":[1,2],"description":"1=natural, 2=jurídica.","default":2},"descActividad":{"type":"string","minLength":5,"maxLength":150,"description":"REQUIRED."},"telefono":{"type":"string","description":"Receptor en el exterior: usá formato internacional con prefijo + (+504 7660-4544). Sin prefijo se asume el país de `codPais`. Para entrega por WhatsApp se interpreta a E.164; si no es válido, se omite ese canal sin bloquear la emisión.","example":"+1 213 373 4253"},"correo":{"type":"string","format":"email","description":"Si pedís entrega por correo y va vacío o inválido, ese canal se omite sin bloquear la emisión."}}},"tipoMoneda":{"type":"string","default":"USD"},"codIncoterms":{"type":"string","description":"CAT-031."},"descIncoterms":{"type":"string"},"flete":{"type":"number"},"seguro":{"type":"number"},"regimen":{"type":"string","description":"CAT-028 régimen aduanero."},"observaciones":{"type":"string","minLength":1,"maxLength":3000,"description":"resumen.observaciones: nota libre registrada en el DTE oficial. Omitir o null = sin observación."}}},"InvalidarRequest":{"type":"object","required":["tipoInvalidacion","motivoInvalidacion","responsable","solicita"],"properties":{"tipoInvalidacion":{"type":"integer","enum":[1,2,3],"description":"1=error, 2=rescindir, 3=medicamentos."},"motivoInvalidacion":{"type":"string"},"responsable":{"$ref":"#/components/schemas/Persona"},"solicita":{"$ref":"#/components/schemas/Persona"}}},"InvalidarEventoRequest":{"type":"object","required":["motivoInvalidacion","responsable","solicita"],"properties":{"motivoInvalidacion":{"type":"string","minLength":5,"maxLength":200,"description":"Descripción del error que ocasiona la invalidación del evento."},"responsable":{"$ref":"#/components/schemas/Persona"},"solicita":{"$ref":"#/components/schemas/Persona"}}},"RetornoRequest":{"type":"object","required":["items","motivoRetorno"],"properties":{"items":{"type":"array","minItems":1,"items":{"type":"object","required":["codigoGeneracion","descripcion","precioUni"],"properties":{"tipoItem":{"type":"integer","enum":[1,2,3,4]},"codigoGeneracion":{"type":"string","description":"codGen del DTE original."},"cantidad":{"type":"number","default":1},"precioUni":{"type":"number","description":"Precio unitario NETO (sin débito fiscal): el MH valida el total del retorno contra la venta neta del DTE original. Para retornar el total de una Factura de $1.13 IVA incluido → precioUni $1.00, ivaItem $0.13."},"descripcion":{"type":"string"},"ventaGravada":{"type":"number","description":"Neto, sin IVA."},"ivaItem":{"type":"number","description":"IVA del ítem — informativo (Anexo III campo 83)."}}}},"motivoRetorno":{"type":"string"}}},"LoteRequest":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["tipo","payload"],"properties":{"tipo":{"type":"string","enum":["01","03","04","05","06","07","08","09","11","14","15"]},"payload":{"type":"object","additionalProperties":true,"description":"Mismo shape que el endpoint individual del tipo."}}}},"contingencia":{"type":"boolean","default":false,"description":"Saltea la restricción horaria (para DTEs emitidos en contingencia)."}}},"LoteResponse":{"type":"object","properties":{"codigoLote":{"type":"string"},"estadoLote":{"type":"string"},"descripcionMsg":{"type":"string"},"total":{"type":"integer"},"dtes":{"type":"array","items":{"type":"object","properties":{"dteId":{"type":"string"},"codigoGeneracion":{"type":"string"},"numeroControl":{"type":"string"},"tipo":{"type":"string"}}}}}}}}}