Saltar al contenido principal

Manejo de errores

Todos los errores se devuelven en formato Problem JSON (RFC 7807) con Content-Type: application/problem+json.

Estructura

{
"type": "https://api-docs.maxpay.com.ar/errors/receivable-account-already-exists",
"title": "Receivable account already exists",
"status": 409,
"detail": "Ya existe una cuenta recaudadora para este cliente con la misma moneda.",
"instance": "/v1/receivable-accounts",
"code": "receivable-account-already-exists",
"requestId": "req_b3f8a1c2d4e5f6789012345678901234",
"existingResourceId": 1042
}
CampoTipoSiempre presenteDescripción
typeURIURI que identifica el tipo de problema. Apunta al catálogo de errores.
titlestringResumen corto en inglés. Estable entre versiones del problema.
statusintegerCódigo HTTP que corresponde.
detailstringDescripción humana en español del problema concreto. Puede variar entre ocurrencias.
instanceURI relativaPath del request que generó el error.
codestringIdentificador estable del error (kebab-case). Apto para mapear en el ERP.
requestIdstringID único del request. Inclulir en reportes de soporte.
invalidParamsarraySolo en 400Detalle de campos inválidos.
Otros camposvariableNoContexto adicional específico del problema (ej. existingResourceId, candidates).

Errores de validación (400)

Cuando el problema es el formato del request (campos faltantes, tipos incorrectos, valores fuera de rango), la respuesta incluye invalidParams:

{
"type": "https://api-docs.maxpay.com.ar/errors/validation",
"title": "Validation error",
"status": 400,
"detail": "El request tiene campos inválidos.",
"instance": "/v1/receivables",
"code": "validation",
"requestId": "req_...",
"invalidParams": [
{ "name": "amount", "reason": "El monto debe ser positivo" },
{ "name": "currencyCode", "reason": "El código de moneda es requerido" }
]
}

Categorías por código HTTP

HTTPCategoríaEjemplos
400Formato del request inválidoSchema mal, tipos incorrectos, campos faltantes
401Autenticación fallidaToken inválido, expirado, ausente
403Autorizado pero sin permisoFalta scope en el token, recurso pertenece a otro customer
404Recurso no existeID inexistente o no accesible
409Conflicto de estadoRecurso ya existe, idempotency-key reusada con body distinto
422Regla de negocioCuenta no habilitada para deudas, transición de estado inválida
429Rate limit excedidoDemasiados requests por minuto
500Error internoBug en Max Pay
502/504Falla en proveedor externoProveedor bancario no disponible, timeout en COELSA

Catálogo completo

Ver Catálogo de errores para la lista exhaustiva de códigos, mensajes y contexto.

Manejo recomendado en el ERP

async function callMaxpay(path, options) {
const res = await fetch(`${BASE_URL}${path}`, options);

if (res.ok) return await res.json();

const problem = await res.json();
const requestId = problem.requestId;

switch (problem.code) {
case 'idempotency-key-reuse':
// Cuerpo diferente con misma key — bug del integrador, alertar
throw new IntegrationError(problem, requestId);

case 'receivable-account-already-exists':
// Recurso ya creado — usar el ID existente
return await callMaxpay(`/v1/receivable-accounts/${problem.existingResourceId}`, {
method: 'GET',
headers: options.headers
});

case 'rate-limit-exceeded':
const retryAfter = parseInt(res.headers.get('Retry-After'), 10);
await sleep(retryAfter * 1000);
return await callMaxpay(path, options);

case 'external-provider-unavailable':
case 'external-provider-timeout':
// Reintentar con backoff exponencial
throw new RetryableError(problem, requestId);

default:
throw new MaxpayError(problem, requestId);
}
}

Para reportar un incidente

Si necesitás reportar un error a soporte, incluí siempre el requestId y el code. Esto permite encontrar la traza completa del request en nuestros logs.