Convenciones
Esta página describe las reglas transversales del API. Léela una vez y aplican a todos los endpoints.
Identificadores de documento
Cada DTE emitido por el API tiene tres identificadores, pensados para usos distintos:
| Identificador | Quién lo asigna | Formato | Uso típico |
|---|---|---|---|
document_id | Ocote | UUID v4 | Identificador interno del API. Se devuelve en el response. |
external_ref | Tú | Texto libre (máx. 100 caracteres) | Identificador que tú controlas. Idempotencia y retry. |
control_number | MH (fijado por Ocote) | DTE-{tipo}-{sucursal}{pos}-{15 dígitos} | Correlativo fiscal. El que aparece en el JSON firmado y en el ticket. |
Reglas importantes
- El
external_refes único por empresa. Dos emisiones del mismo API key con el mismoexternal_refse referencian al mismo documento. Ver Retry e idempotencia. - El
control_numbernunca se regenera. Una vez asignado, queda fijo aun en reintentos. - Los endpoints que reciben un
id_or_refaceptan los tres identificadores indistintamente — UUID o tuexternal_reffuncionan en/status/{id},/invalidate/{id},/file/{id}, etc.
El external_ref es opcional pero altamente recomendado
Si no envías external_ref en el request, Ocote asigna uno automáticamente derivado del UUID. Funciona, pero pierdes la capacidad de encontrar el documento desde tu lado sin guardar el UUID devuelto, y pierdes la ventana de retry idempotente ante un timeout de red.
Recomendación: genera tu propio external_ref con una convención legible (VENTA-2026-000042, INV-A1B2C3, lo que sea), guárdalo antes de llamar al API, y mándalo en cada request.
HTTP status codes
El API sigue convenciones REST estándar con un matiz importante para emisión:
| Código | Cuándo ocurre | Qué hacer |
|---|---|---|
200 OK | La operación se registró en Ocote. Puede ser éxito, contingencia o rechazo por MH. | Leer los flags del body. |
400 Bad Request | Error de validación del payload (campo faltante, NIT mal formado, cantidad negativa). | Corregir el payload. |
401 Unauthorized | API key ausente, inválida o empresa desactivada. | Revisar la key. |
404 Not Found | Documento no encontrado por id_or_ref, o ruta inexistente. | Verificar el identificador. |
409 Conflict | Operación incompatible con el estado actual (p.ej. invalidar un documento ya invalidado). | Consultar /status/{id} para ver el estado actual. |
429 Too Many Requests | Rate limit excedido. | Esperar y respetar Retry-After. Ver Rate limits. |
500 Internal Server Error | Error no controlado en Ocote. | Reintentar tras unos segundos; si persiste, contactar a Ocote. |
200 OK no siempre significa "MH aceptó"Un response 200 con rejected: true significa: Ocote registró tu petición correctamente, pero el MH rechazó el documento por datos del receptor. Corrige y reintenta con el mismo external_ref.
Ver la tabla completa de flags en Respuestas y estados.
Encoding y content-type
- Request: todas las peticiones POST deben llevar
Content-Type: application/jsony body codificado en UTF-8. - Response: JSON UTF-8. Los acentos y caracteres españoles no requieren escape.
- Archivos descargados: ticket en
application/pdf, JSON enapplication/json(con el JWS completo incluyendo sello MH).
Fechas y zonas horarias
- Todas las fechas en responses son ISO 8601 con zona horaria. Ocote corre en
America/El_Salvador(UTC-6). Ejemplo:2026-04-21T10:42:15-06:00. - Para filtros por fecha en endpoints de listado/consulta, usa formato
YYYY-MM-DD(p.ej.date_from=2026-04-01). Se interpretan en hora local (UTC-6). - No necesitas enviar fechas en los requests de emisión. Ocote asigna el timestamp de posteo al momento de recibir la petición aceptada.
Montos, moneda y decimales
- Moneda única: USD. El API no acepta ni devuelve montos en otra moneda. El Salvador opera en dólar como moneda de curso legal para DTE.
- Todos los precios unitarios se envían con IVA incluido en ventas locales (tipos 01, 03, 14). Ocote desglosa internamente base gravable y 13 % de IVA.
- Decimales: acepta hasta 2 decimales en montos y hasta 8 decimales en cantidades (para unidades fraccionarias de tipo peso/volumen). Los montos se redondean a 2 decimales en el DTE final según reglas del MH.
- No envíes símbolos de moneda ni separadores de miles. Correcto:
100.00. Incorrecto:"$100","1,000.00".
Valores enumerados que no son autodescriptivos
Algunos campos del MH usan códigos numéricos que no se pueden inferir de contexto. Los más frecuentes:
| Campo | Valores | Significado |
|---|---|---|
doc_type | "01", "03", "05", "11", "14" | Factura, CCF, Nota de Crédito, Factura Exportación, Sujeto Excluido. |
type_contributor | 1, 2, 3, 4 | Pequeño, Mediano, Grande, Gobierno. |
transaction_condition | 1, 2, 3 | Contado, Crédito, Otro. |
payment_method | "01", "02", "03", "05", "08", … | Efectivo, Tarjeta Débito, Tarjeta Crédito, Transferencia, Dinero Electrónico. Ver Catálogos MH. |
Campos opcionales vs omitidos
El API distingue entre campo ausente (no lo mandaste) y campo enviado con valor vacío. Regla práctica:
- Si un campo es opcional y no lo necesitas, omítelo. No mandes
"email": ""ni"email": nullsi no quieres email; simplemente no incluyas la llave. - Los valores
nullexplícitos se aceptan como equivalentes a "omitido" en la mayoría de campos, pero algunos validadores del MH los rechazan. Prefiere omitir.
Versionado
El API está en su primera versión pública estable. No hay prefijo de versión en la URL (/api/connect/... no /api/connect/v1/...). Los cambios futuros seguirán estas reglas:
- Aditivos no rompen. Agregar campos nuevos al response o parámetros opcionales al request nunca requerirá cambios del cliente.
- Cambios que rompen se comunican con preaviso y se introducen en una ruta
/api/connect/v2/dedicada, manteniendo la v1 por un periodo de deprecación.
Ver Changelog para el historial de cambios.