Ir al contenido

Códigos de error

Todos los errores de la API de Sangho devuelven un objeto JSON estructurado y plano (sin claves anidadas) con un código de error de negocio, un mensaje legible y un enlace directo a la sección de esta página que lo explica. Al hacer clic en un enlace doc_url recibido en su consola o en sus registros, llegará aquí y se resaltará automáticamente la fila del código correspondiente.

Estructura de un error

ChampTypeRequisDescription
typestringRequisCategoría del error: uno de los 7 valores que se indican a continuación. Útil para un tratamiento genérico (mostrar un mensaje por categoría).
codestringRequisCódigo de negocio preciso de Sangho, p. ej. AMOUNT_TOO_SMALL. Es la fuente de verdad para la gestión detallada de los casos de error y debe preferirse a type y al código HTTP.
messagestringRequisDescripción legible del error, en francés
statusintegerRequisCódigo HTTP asociado: 400, 401, 403, 404, 409, 422, 429, 500
doc_urlstringOptionnelEnlace directo a la fila de esta página correspondiente al código, p. ej. https://docs.sangho.ga/errors#AMOUNT_TOO_SMALL
paramstringOptionnelCampo implicado en los errores de validación (422)
errorsobjectOptionnelDetalle por campo para los errores de validación de varios campos — {`{ "amount": ["..."] }`}
request_idstringOptionnelIdentificador de la solicitud, que debe facilitar al soporte si es necesario

Las 7 categorías (type)

Cada error pertenece a una de estas 7 categorías. El SDK de JavaScript expone la misma taxonomía en err.type, lo que resulta práctico para un tratamiento genérico por ramas (reintento, redirección al inicio de sesión, etc.) antes de descender al nivel del code preciso si es necesario.

typeEstados HTTP típicosSignificado
AUTHENTICATION_ERROR401Clave API ausente, no válida o caducada
PERMISSION_ERROR403Identidad reconocida, pero acción no autorizada (clave pública, cuenta restringida, plan insuficiente…)
NOT_FOUND_ERROR404Recurso no encontrado
CONFLICT_ERROR409Conflicto: idempotency key reutilizada, duplicado
VALIDATION_ERROR422Solicitud sintácticamente correcta pero no válida para el negocio
RATE_LIMIT_ERROR429Cuota de llamadas superada
API_ERROR500Error en Sangho

Códigos HTTP estándar

El código HTTP indica la categoría del error. Utilícelo para orientar su lógica de reintentos y de visualización.

CodeDescription
200Éxito: solicitud procesada
201Recurso creado correctamente
400Solicitud no válida: JSON mal formado o cabeceras incorrectas
401Clave API ausente, caducada o no válida
403Permiso insuficiente: la App no tiene acceso a este recurso o a esta acción
404Recurso no encontrado: ID incorrecto o recurso eliminado
409Conflicto: idempotency key reutilizada con un cuerpo de solicitud distinto
422Validación de negocio fallida: regla de negocio no respetada
429Demasiadas solicitudes: se ha alcanzado el límite de peticiones (rate limiting), aplique un backoff
500Error interno de Sangho: vuelva a intentarlo con un backoff exponencial

Códigos de negocio

Todos los códigos siguen el estándar SCREAMING_SNAKE_CASE, sin prefijo. Enlace sus gestores de errores con code y no con el estado HTTP: el código es la fuente de verdad.

Autenticación — 401

CodeDescription
MISSING_API_KEYClave API ausente: indíquela mediante Authorization: Bearer <clave>
INVALID_API_KEYClave API no válida, revocada o mal formada
EXPIRED_API_KEYClave API caducada: genere una nueva desde su panel
INVALID_TOKENToken JWT no válido o caducado
AUTHENTICATION_FAILEDFallo de autenticación genérico: compruebe la cabecera Authorization

Autorización — 403

Estos errores se devuelven cuando se reconoce la identidad, pero la operación no está autorizada para esta clave, esta cuenta o este plan.

CodeDescription
PERMISSION_DENIEDPermiso denegado: su clave no está autorizada para realizar esta acción sobre este recurso
PUBLIC_KEY_NOT_ALLOWEDEsta ruta requiere una clave secreta (sk_prod_ o sk_test_). No exponga nunca su clave secreta en el cliente
PLATFORM_PARTNER_REQUIREDEsta ruta (connect.*) está reservada a las Apps con el estado de Socio de Plataforma: haga la solicitud desde su panel, la aprobación es manual
APP_DISABLEDLa aplicación está desactivada: reactívela desde su panel
APP_NOT_VERIFIEDAplicación no verificada: KYC pendiente de aprobación
INSUFFICIENT_PERMISSIONSPermisos insuficientes para este recurso o esta acción
SANDBOX_ONLYEsta ruta está reservada al entorno sandbox: utilice una clave sk_test_
CURRENCY_NOT_IN_PLANLa moneda solicitada está activa en Sangho pero no está incluida en su plan actual: pase a un plan superior para activarla
COMPANY_BLACKLISTEDEsta cuenta ha sido incluida en la lista negra y ya no tiene acceso a la plataforma: contacte con el soporte
COMPANY_PAYMENTS_DISABLEDLos pagos entrantes están actualmente desactivados para esta cuenta
COMPANY_PAYOUTS_DISABLEDLas transferencias salientes están actualmente desactivadas para esta cuenta
COMPANY_SANDBOX_ONLYEsta cuenta está restringida por el momento al modo de prueba (sandbox)
COMPANY_KYC_REQUIREDSe requiere la verificación KYC antes de poder procesar pagos
Attention

El código PERMISSION_DENIED lo devuelve en particular POST /v1/reset cuando se invoca con una clave de producción (sk_prod_). Esta ruta borra todos los datos de la aplicación y solo es accesible en el sandbox. Utilice una clave sk_test_ para acceder a ella.

Recurso no encontrado — 404

CodeDescription
NOT_FOUNDRecurso no encontrado: ID incorrecto, recurso eliminado o acceso prohibido
CUSTOMER_NOT_FOUNDNingún Customer con este identificador para esta aplicación
PRODUCT_NOT_FOUNDNingún Product con este identificador
PAYMENT_INTENT_NOT_FOUNDNingún PaymentIntent con este identificador
TRANSACTION_NOT_FOUNDNinguna Transaction con este identificador
REFUND_NOT_FOUNDNingún Refund con este identificador
INVOICE_NOT_FOUNDNinguna Invoice con este identificador
SUBSCRIPTION_NOT_FOUNDNinguna Subscription con este identificador
CHECKOUT_SESSION_NOT_FOUNDNinguna CheckoutSession con este identificador
PAYMENT_METHOD_NOT_FOUNDNingún PaymentMethod con este identificador
RECEIPT_NOT_FOUNDNingún Receipt con este identificador
WEBHOOK_NOT_FOUNDNingún Webhook con este identificador
SEARCH_NO_RESULTSNingún resultado para la búsqueda: compruebe el parámetro ?search=

Conflicto — 409

CodeDescription
IDEMPOTENCY_CONFLICTYa se ha procesado una solicitud con la misma Idempotency-Key con un cuerpo de solicitud distinto
DUPLICATE_EMAILYa existe un Customer con este correo electrónico para esta aplicación
DUPLICATE_SKUYa existe un Product con este SKU

Validación de negocio — 422

CodeDescription
VALIDATION_ERRORLos datos facilitados no son válidos: consulte el campo errors para ver el detalle por campo
MISSING_FIELDFalta un campo obligatorio en la solicitud
INVALID_FIELDEl valor de un campo es incorrecto o está fuera de los valores aceptados
INVALID_FILTER_PARAMUn parámetro de filtro (?param=) no corresponde a ningún campo del modelo
INVALID_CURRENCYLa moneda facilitada no es un código ISO 4217 reconocido o no está activada en Sangho — véanse las monedas admitidas
AMOUNT_TOO_SMALLImporte inferior al mínimo autorizado (100 XAF por defecto)
AMOUNT_TOO_LARGEImporte superior al límite autorizado
INVALID_STATUS_TRANSITIONLa transición de estado solicitada está prohibida (p. ej. reabrir una Invoice anulada)
PAYMENT_INTENT_UNCANCELABLENo se puede cancelar este PaymentIntent en su estado actual
PAYMENT_INTENT_NOT_CONFIRMABLENo se puede confirmar este PaymentIntent en su estado actual
PAYMENT_INTENT_NOT_CAPTURABLENo se puede capturar: el estado debe ser requires_capture
CAPTURE_AMOUNT_EXCEEDS_ORIGINALEl importe que se va a capturar supera el importe original del PaymentIntent
CHECKOUT_SESSION_EXPIREDLa sesión de checkout ha caducado: pida al cliente que inicie una nueva
SUBSCRIPTION_ALREADY_CANCELEDEsta Subscription ya está cancelada y no se puede cancelar de nuevo
INVOICE_NOT_DRAFTABLEEsta Invoice no está en un estado que permita volver a borrador

Rate limiting — 429

CodeDescription
RATE_LIMIT_EXCEEDEDCuota de llamadas a la API superada: consulte la cabecera Retry-After para conocer el tiempo de espera
TOO_MANY_REQUESTSDemasiadas solicitudes simultáneas desde esta clave API

Pagos y Mobile Money

CodeDescription
INSUFFICIENT_FUNDSFondos insuficientes por parte del comprador (Mobile Money o tarjeta)
PAYMENT_METHOD_NOT_SUPPORTEDMétodo de pago no activado para esta cuenta de comerciante
MOBILE_MONEY_TIMEOUTEl comprador no ha confirmado el pago en el plazo previsto (por lo general, 3 min)
MOBILE_MONEY_REJECTEDEl comprador ha rechazado la solicitud de pago en su teléfono
MOBILE_MONEY_NUMBER_INVALIDNúmero de Mobile Money incorrecto o no registrado en el operador
MOBILE_MONEY_LIMIT_REACHEDSe ha alcanzado el límite diario o mensual del operador para este número
CUSTOMER_BLACKLISTEDEl Customer está en la lista negra: no se autoriza ningún pago

Webhooks e integraciones

CodeDescription
WEBHOOK_SIGNATURE_INVALIDFirma HMAC-SHA256 no válida: compruebe su webhook secret
WEBHOOK_ENDPOINT_UNREACHABLELa URL del webhook no responde: Sangho lo reintentará según la política de reintentos
TERMINAL_OFFLINEEl terminal de Sangho no es accesible: compruebe la conexión de red
PDF_NOT_AVAILABLEEl PDF de este documento aún no se ha generado: vuelva a intentarlo en unos instantes
METHOD_NOT_ALLOWEDMétodo HTTP no autorizado en este endpoint

Error del servidor — 500

CodeDescription
INTERNAL_ERRORError interno de Sangho: nuestro equipo ha sido notificado. Vuelva a intentarlo con un backoff exponencial
DATABASE_ERRORError de base de datos: temporal, vuelva a intentarlo en unos instantes
UPSTREAM_ERRORError de un servicio de terceros (operador, pasarela): vuelva a intentarlo o contacte con el soporte

Estrategia de reintentos recomendada

No todos los errores son iguales. El SDK de JavaScript ya aplica esta lógica automáticamente (véase el SDK de JavaScript), lo que resulta útil saber si llama directamente a la API.

Código HTTPAcción recomendada
400 / 422No reintentar: corregir los parámetros de la solicitud
401 / 403No reintentar: comprobar la clave API, los permisos o el plan
404No reintentar: comprobar el ID del recurso
409Recuperar la respuesta idempotente ya generada: no crear un duplicado
429Esperar el tiempo indicado en la cabecera Retry-After y después reintentar
500Reintentar con backoff exponencial (1 s → 2 s → 4 s → 8 s, máx. 3 intentos)
Note

La cabecera Retry-After se incluye en todas las respuestas 429. Su valor se expresa en segundos.

Estructura de un error

ResponseRespuesta — AMOUNT_TOO_SMALL
json
{
  "status": 422,
  "type": "VALIDATION_ERROR",
  "code": "AMOUNT_TOO_SMALL",
  "message": "Le montant est trop faible. Le minimum est de 100 XAF.",
  "param": "amount",
  "doc_url": "https://docs.sangho.ga/errors#AMOUNT_TOO_SMALL",
  "request_id": "req_5d0cc04ea0664a50a14a247f"
}

Moneda fuera del plan (403)

ResponseRespuesta — CURRENCY_NOT_IN_PLAN
json
{
  "status": 403,
  "type": "PERMISSION_ERROR",
  "code": "CURRENCY_NOT_IN_PLAN",
  "message": "La devise 'USD' n'est pas incluse dans votre plan actuel.",
  "doc_url": "https://docs.sangho.ga/errors#CURRENCY_NOT_IN_PLAN",
  "request_id": "req_5d0cc04ea0664a50a14a247f"
}

Acceso denegado — solo sandbox (403)

ResponseRespuesta — PERMISSION_DENIED
json
{
  "status": 403,
  "type": "PERMISSION_ERROR",
  "code": "PERMISSION_DENIED",
  "message": "Le reset est uniquement disponible en environnement sandbox. Utilisez une clé sandbox (sk_test_*) pour accéder à cette route.",
  "doc_url": "https://docs.sangho.ga/errors#PERMISSION_DENIED",
  "request_id": "req_5d0cc04ea0664a50a14a247f"
}

Idempotency-Key reutilizada (409)

ResponseRespuesta — IDEMPOTENCY_CONFLICT
json
{
  "status": 409,
  "type": "CONFLICT_ERROR",
  "code": "IDEMPOTENCY_CONFLICT",
  "message": "Une requête avec la même clé d'idempotence est déjà en cours ou a déjà produit un résultat différent.",
  "doc_url": "https://docs.sangho.ga/errors#IDEMPOTENCY_CONFLICT",
  "request_id": "req_9a1bc23de4567f89b01c234d"
}

Error de validación (422)

ResponseRespuesta — VALIDATION_ERROR
json
{
  "status": 422,
  "type": "VALIDATION_ERROR",
  "code": "VALIDATION_ERROR",
  "message": "L'email est requis.",
  "errors": {
    "email": ["Ce champ est obligatoire."],
    "amount": ["La valeur doit être un entier positif."]
  },
  "doc_url": "https://docs.sangho.ga/errors#VALIDATION_ERROR",
  "request_id": "req_9a1bc23de4567f89b01c234d"
}

Rate limit alcanzado (429)

ResponseRespuesta — RATE_LIMIT_EXCEEDED
json
{
  "status": 429,
  "type": "RATE_LIMIT_ERROR",
  "code": "RATE_LIMIT_EXCEEDED",
  "message": "Limite de requêtes atteinte. Réessayez dans 60 secondes.",
  "retry_after": 60,
  "doc_url": "https://docs.sangho.ga/errors#RATE_LIMIT_EXCEEDED",
  "request_id": "req_2f4a8b1c9e3d5f70a0b2c4d6"
}

Recurso no encontrado (404)

ResponseRespuesta — CUSTOMER_NOT_FOUND
json
{
  "status": 404,
  "type": "NOT_FOUND_ERROR",
  "code": "CUSTOMER_NOT_FOUND",
  "message": "Aucun(e) Customer avec l'identifiant 'cust_xyz123'.",
  "doc_url": "https://docs.sangho.ga/errors#CUSTOMER_NOT_FOUND",
  "request_id": "req_7c3e5a2d1b8f4096e5d7c9b1"
}

Gestión de errores — SDK

bash
# Les erreurs HTTP retournent toujours un JSON plat (aucune clé imbriquée)
# Capturez le status HTTP et lisez le champ "code" directement
HTTP_STATUS=$(curl -s -o response.json -w "%{http_code}" \
  -X POST https://api.sangho.ga/v1/payment-intents/ \
  -H "Authorization: Bearer sk_test_xxxx" \
  -H "Content-Type: application/json" \
  -d '{"amount": -1, "currency": "XAF"}')


if [ "$HTTP_STATUS" != "200" ] && [ "$HTTP_STATUS" != "201" ]; then
  ERROR_CODE=$(cat response.json | python3 -c "import sys,json; print(json.load(sys.stdin)['code'])")
  echo "Erreur: $ERROR_CODE (HTTP $HTTP_STATUS)"
fi