Saltar al contenido principal

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:

IdentificadorQuién lo asignaFormatoUso típico
document_idOcoteUUID v4Identificador interno del API. Se devuelve en el response.
external_refTexto libre (máx. 100 caracteres)Identificador que tú controlas. Idempotencia y retry.
control_numberMH (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_ref es único por empresa. Dos emisiones del mismo API key con el mismo external_ref se referencian al mismo documento. Ver Retry e idempotencia.
  • El control_number nunca se regenera. Una vez asignado, queda fijo aun en reintentos.
  • Los endpoints que reciben un id_or_ref aceptan los tres identificadores indistintamente — UUID o tu external_ref funcionan 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ódigoCuándo ocurreQué hacer
200 OKLa operación se registró en Ocote. Puede ser éxito, contingencia o rechazo por MH.Leer los flags del body.
400 Bad RequestError de validación del payload (campo faltante, NIT mal formado, cantidad negativa).Corregir el payload.
401 UnauthorizedAPI key ausente, inválida o empresa desactivada.Revisar la key.
404 Not FoundDocumento no encontrado por id_or_ref, o ruta inexistente.Verificar el identificador.
409 ConflictOperación incompatible con el estado actual (p.ej. invalidar un documento ya invalidado).Consultar /status/{id} para ver el estado actual.
429 Too Many RequestsRate limit excedido.Esperar y respetar Retry-After. Ver Rate limits.
500 Internal Server ErrorError 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/json y 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 en application/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:

CampoValoresSignificado
doc_type"01", "03", "05", "11", "14"Factura, CCF, Nota de Crédito, Factura Exportación, Sujeto Excluido.
type_contributor1, 2, 3, 4Pequeño, Mediano, Grande, Gobierno.
transaction_condition1, 2, 3Contado, 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": null si no quieres email; simplemente no incluyas la llave.
  • Los valores null explí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.