Saltar al contenido principal

Errores

Todos los errores de /v1 tienen la misma forma, sin importar el endpoint ni el código HTTP:

{
"code": "PRODUCT_NOT_FOUND",
"message": "No product mapping found for external id SKU-WEB-HOSTING-01."
}
  • code — estable y legible por máquina. Programa contra esto.
  • message — explicación para humanos. Útil en logs y en tu pantalla de soporte, pero su redacción puede cambiar sin aviso. No lo parsees.

Cómo interpretar el HTTP status

StatusSignificado¿Reintentar?
400Tu solicitud está mal. Arregla el body y vuelve a mandar.No, tal cual
401Credencial ausente o inválida.No
403Credencial válida, pero la empresa no tiene la integración habilitada.No
404No existe dentro de tu empresa.No
409Conflicto: duplicado, key reutilizada con otro body, o configuración incompleta de la empresa.No
422Solicitud bien formada pero pide algo que v1 no hace.No
500Falla nuestra.Sí, con backoff y la misma Idempotency-Key

Regla general: solo los 5xx y los timeouts se reintentan.

Catálogo de códigos

Autenticación y habilitación

codeHTTPQué hacer
MISSING_API_KEY401Manda Authorization: Bearer <key>.
INVALID_API_KEY401La key no existe, fue revocada o expiró. Emite otra.
INTEGRATION_NOT_ENABLED403Tu empresa no tiene la integración activada. Contacta a Contadito.

Configuración de la empresa (no lo arreglas tú)

Estos significan que la integración está encendida pero incompleta o desactualizada del lado de la configuración. Todos son 409 y todos se resuelven en la app de Contadito, no en tu código.

codeQué falta
INTEGRATION_MISSING_EMISSION_POINTPunto de emisión por defecto.
INTEGRATION_MISSING_CREATOR_USERUsuario emisor por defecto.
INTEGRATION_MISSING_PRICE_TYPELista/tipo de precio por defecto.
INTEGRATION_MISSING_PAYMENT_TERMINALConfiguración de cobro por defecto. Solo lo exige la emisión real, no la previsualización.
INTEGRATION_EMISSION_POINT_NOT_FOUNDEl punto de emisión configurado ya no existe.
INTEGRATION_PAYMENT_TERMINAL_NOT_FOUNDLa configuración de cobro ya no existe.

Si los ves en producción, la acción correcta es alertar a tu equipo de soporte y dejar la venta en cola: reintentar no ayuda hasta que alguien corrija la configuración.

Productos y precios

codeHTTPQué pasó
PRODUCT_NOT_FOUND400Ese externalProductId no está mapeado. El error más común en integraciones nuevas. Pide el mapeo.
PRICE_NOT_FOUND409El producto existe pero no tiene precio en la lista configurada.
ITEM_MISSING_PRODUCT_REFERENCE400Una línea no referencia ningún producto.
ITEM_AMBIGUOUS_PRODUCT_REFERENCE400Una línea referencia más de un producto.
INVALID_TAX_RATE409El producto tiene una tasa de ISV inválida en el catálogo.
DISCOUNT_POLICY_NOT_FOUND409La política de descuento aplicable no existe.
DISCOUNT_POLICY_UNAVAILABLE409La política existe pero no está disponible ahora.
INVALID_DISCOUNT_POLICY409La política está mal configurada.

La solicitud

codeHTTPQué pasó
VALIDATION_FAILED400El body no pasó validación (falta un campo, tipo equivocado, o mandaste un campo que no existe), o un query param como page/limit no es un entero ≥ 1. message dice cuál.
MISSING_IDEMPOTENCY_KEY400Falta el header Idempotency-Key en POST /v1/invoices. POST /v1/invoices/preview no lo pide.
IDEMPOTENCY_KEY_REQUEST_MISMATCH409Reusaste una key con un body diferente. Ver Idempotencia.
EXTERNAL_INVOICE_NO_ITEMS400items vacío. Se requiere al menos una línea.
EMPTY_ITEMS400Igual que el anterior, detectado por el motor de totales.
INVALID_NUMBER400Un número no es válido (cantidad cero o negativa, por ejemplo).
INVALID_REQUEST400La solicitud es inconsistente. Lee message.
EXTERNAL_INVOICE_CLIENT_NOT_FOUND400Ese clientId no existe en tu empresa.
EXTERNAL_INVOICE_EXONERATION_REQUIRES_CLIENT400Una venta exonerada necesita clientId.
EXTERNAL_INVOICE_EXONERATION_REQUIRES_RTN400El cliente de una venta exonerada debe tener RTN (legalId).
INVALID_RTN_FORMAT400El RTN debe ser exactamente 14 dígitos.
UQ_CLIENT_CODE_COMPANY409Ya existe un cliente con ese código en tu empresa.
UQ_IHCAFE_CODE_CLIENT409Ya existe un cliente con ese código IHCAFE.
EXTERNAL_INVOICE_NOT_FOUND404Esa factura no existe dentro de tu empresa.
EXTERNAL_INVOICE_CREDIT_NOT_SUPPORTED422isCredit: true está reservado para v2.

Del lado nuestro

codeHTTPQué hacer
INTERNAL_ERROR500Algo falló en Contadito. Reintenta con backoff y la misma Idempotency-Key. Si persiste, avísanos con la hora y la key.

Cómo manejarlos en código

const NO_REINTENTABLES = new Set([
'MISSING_API_KEY',
'INVALID_API_KEY',
'VALIDATION_FAILED',
'PRODUCT_NOT_FOUND',
'IDEMPOTENCY_KEY_REQUEST_MISMATCH',
'EXTERNAL_INVOICE_CREDIT_NOT_SUPPORTED',
]);

const REQUIEREN_SOPORTE = (code) =>
code === 'INTEGRATION_NOT_ENABLED' || code.startsWith('INTEGRATION_');

function manejar(status, body) {
if (status >= 500) return 'reintentar';
if (REQUIEREN_SOPORTE(body.code)) return 'encolar_y_alertar';
if (NO_REINTENTABLES.has(body.code)) return 'fallar_y_registrar';
return 'fallar_y_registrar';
}
aviso

Nunca hagas if (message === '...')

message es texto para humanos y su redacción cambia. Toda tu lógica va sobre code y el status HTTP.