Errores y límites

Cómo interpretar las respuestas de error de la API, qué significan los códigos por dominio y cómo manejar rate limits y reintentos.

Anatomía de un error

Todas las respuestas de error comparten la misma estructura. El campo code es un identificador estable con formato {dominio}_{número} que puedes usar para manejar cada caso de forma programática (no dependas del texto de message, que es legible pero puede cambiar).

{
  "success": false,
  "message": "API Key inválida o no existe.",
  "status": 401,
  "code": "auth_05"
}
CampoDescripción
successfalse en todo error.
messageDescripción legible en español.
statusCategoría del error dentro del cuerpo. No dependas de él ni del código HTTP de transporte: la API suele responder HTTP 200 incluso en errores.
codeCódigo estructurado {dominio}_{número}.
request_idUUID de seguimiento (presente en errores 500). Inclúyelo al contactar a soporte.

Guarda el request_id junto con el log de la operación, pero no lo reutilices como identificador propio de mensajes, campañas o transacciones: para eso usa el reference que devuelve cada envío. Los eventos de webhooks son independientes y no incluyen el request_id de la petición original.

Códigos HTTP

HTTPSignificado¿Reintentar?
200Éxito.No aplica
400Error de validación o de lógica de negocio (parámetros, saldo, mensaje).No, corrige la petición.
401API Key ausente, inválida o cuenta deshabilitada.No, revisa tu llave.
403La IP no está en la lista blanca de tu cuenta.No, autoriza la IP en el panel.
429Se excedió el rate limit.Sí, con backoff.
500Error interno del servidor.Sí, con backoff; guarda el request_id.

En la práctica, la mayoría de los errores de validación y de negocio llegan con HTTP 200 en el transporte: la columna anterior es la categoría del error. La forma confiable de detectar un error es success: false + el code; nunca dependas solo del código HTTP.

Excepción: los endpoints OTP v2 (/v2/otp*) sí responden con status HTTP semántico (201, 400, 401, 404, 409, 410, 429, 502…) y usan un envelope propio con slug en error (no code), más hint y next. Solo los errores de autenticación (auth_*), que resuelve la capa común antes de llegar al endpoint, siguen llegando con HTTP 200. Detalle abajo en la sección Verificación OTP.

Códigos por dominio

El prefijo del code indica el área de la API donde se originó la respuesta y el número identifica el caso exacto. Esta es la referencia de los códigos que la API documenta hoy; el message siempre acompaña al code con el detalle en español.

No todos los códigos son errores. Los que aparecen con HTTP 200 (por ejemplo sms_11) indican éxito y llegan con success: true. Por eso revisa siempre success antes que el code.

Autenticación y acceso (auth_)

CódigoCategoríaSignificado
auth_01401No se proporcionó API Key.
auth_04403La IP no está en la lista blanca de tu cuenta.
auth_05401API Key inválida o inexistente.
auth_06401Cuenta deshabilitada o suspendida.
auth_deprecated410Usaste el encabezado heredado token; migra al encabezado apikey.

Verificación OTP (otp_)

Los endpoints OTP v2 (/v2/otp, /v2/otp/verify, /v2/otp/status) usan un envelope distinto al resto de la API: el slug estable va en error, el status HTTP es real (la columna HTTP de abajo es el código de transporte que efectivamente recibes) y cada error trae hint (qué hacer, en español) y next (endpoints sugeridos).

{
  "success": false,
  "state": "pending",
  "error": "otp_incorrect_code",
  "message": "El código es incorrecto.",
  "hint": "Código incorrecto. Te quedan 3 intentos.",
  "next": ["/v2/otp/verify", "/v2/otp"],
  "attempts_remaining": 3,
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
errorHTTPSignificado
otp_missing_param400Falta un parámetro obligatorio (hint indica cuál).
otp_invalid_param400Parámetro inválido o que no aplica al endpoint (incluye parámetros de la API OTP anterior).
otp_invalid_channel400channel debe ser sms, whatsapp o voice.
otp_message_invalid400El message no incluye {{code}}/{{company}}, usa caracteres fuera de GSM-7 o excede 160 caracteres.
otp_incorrect_code401Código incorrecto (la respuesta trae attempts_remaining).
otp_insufficient_credits402Saldo insuficiente (incluye code: sms_07, el código estándar de saldo de toda la API).
otp_not_found404No hay verificación activa para el número.
otp_already_verified409El número ya está verificado.
otp_code_expired410El código expiró.
otp_throttled429Cooldown de reenvío (30s) activo; espera resend_available_in segundos (también en el header Retry-After).
otp_max_attempts429Se agotaron los 7 intentos de la ronda; rota el código con code_rotate: true.
otp_internal500Error inesperado; reintenta con backoff y guarda el request_id.
otp_send_failed502El canal no pudo entregar el mensaje.

Envío de mensajes (sms_, whatsapp_)

CódigoCategoríaSignificado
sms_01400Mensaje no definido.
sms_02400Mensaje demasiado largo.
sms_03400Números no definidos.
sms_04400Número con formato incorrecto (deben ser 10 dígitos).
sms_05400Código de país no definido.
sms_06400Nombre de campaña de más de 100 caracteres.
sms_07400Créditos insuficientes.
sms_11200Mensajes enviados correctamente.
sms_15400Más de 500 destinatarios en una petición.
sms_16400Número repetido en la lista de destinatarios.
sms_17400Límite diario de sandbox excedido (1000 envíos de prueba).
sms_18400País no soportado.
sms_19200Envío exitoso a un número fijo (informativo).
sms_20400La fecha programada ya pasó.
sms_21400Formato de fecha inválido.
sms_24400Lada no soportada.
sms_29 / sms_31400Acortador: no se encontró URL en el mensaje / hay más de una URL.
sms_36400channel inválido (solo 1 = SMS o 2 = RCS).
sms_37 / sms_38400RCS: remitente obligatorio / remitente no vinculado a la cuenta.
sms_39 / sms_40400flash inválido (solo 0 o 1) / flash no compatible con RCS.
whatsapp_04 / whatsapp_08400Instancia no definida / la instancia no existe o está inactiva.
whatsapp_21200Mensaje de WhatsApp enviado o programado.
whatsapp_23400Número con formato incorrecto.
whatsapp_28 / whatsapp_38400Mensaje de más de 1000 caracteres / caption de más de 1000 caracteres.
whatsapp_37400URL multimedia inválida o con extensión no permitida.

Contactos y listas (contact_, agenda_)

CódigoCategoríaSignificado
contact_01400list_key no definido.
contact_02400Número no definido.
contact_03400Número con formato incorrecto (mínimo 10 dígitos, solo números).
contact_04 / contact_06400Nombre / email de más de 100 caracteres.
contact_05400Email con formato incorrecto.
contact_07400Lista no encontrada.
contact_13200Contacto agregado.
contact_15200Contacto actualizado.
contact_17400La lista está vinculada a una herramienta y no admite cambios.
contact_19400El contacto no existe.
agenda_01200Lista creada (devuelve list_key).
agenda_02400Nombre de lista no definido.
agenda_03400Ya existe una lista con ese nombre en la cuenta.
change_name_02 / change_name_03400Falta list_key / falta el nuevo nombre.
get_contacts_02400list_key no definido.

Otros dominios

CódigoCategoríaSignificado
credit_01200Consulta de créditos exitosa.
report_01 / report_02400Falta start_date / falta end_date.
report_03400start_date es posterior a end_date.
report_04200Reporte generado.
report_05400Límite de peticiones de reporte excedido.
details_02400campaign_id no definido o no numérico.
details_03 / details_04400La campaña no existe / aún se está procesando.
add_webhook_01200Webhook registrado.
add_webhook_02 a add_webhook_06400URL no definida, formato inválido, estado no definido o inválido, o la URL no respondió a la verificación.
err_03400/500Error genérico; el message describe la causa.
rate_01429Rate limit excedido.
server_01500Error interno del servidor.

¿Recibiste un code que no está en esta tabla? El message de la respuesta describe la causa. Cada endpoint también lista en el API Reference los códigos que puede devolver, por ejemplo /sms/send o /v2/otp/verify.

Errores frecuentes de SMS

// Créditos insuficientes
{ "success": false, "message": "insufficient_credits", "code": "sms_07" }
 
// Mensaje excede el límite de caracteres
{ "success": false, "message": "message_too_long", "code": "sms_02" }

Antes de un envío grande, valida el saldo con /credits/consult para no fallar a mitad de la campaña con sms_07.

Rate limits

EntornoLímiteAl exceder
Producción100 mensajes/segundoHTTP 429, code: rate_01
Sandbox1000 envíos de prueba/díasuccess: false, code: sms_17

Manejo de errores

1

Revisa success primero

Si success es false, no proceses la respuesta como éxito aunque el HTTP sea 200.

2

Ramifica por code, no por message

Usa el code estructurado (sms_07, auth_04, etc.) en tu lógica. El message es para logs y humanos.

3

Reintenta solo 429 y 500

Implementa reintentos con backoff exponencial únicamente en 429 y 500. Los 4xx restantes requieren corregir la petición.

4

Registra el request_id

En errores 500, guarda el request_id y compártelo con soporte para acelerar el diagnóstico.

Con esto puedes manejar cualquier respuesta de la API de forma robusta. Vuelve a la Guía rápida o explora el API Reference.