# Errores y rechazos

## Cuando la API responde con error

El cuerpo siempre trae `error` y, a veces, `detail`:

```json
{ "error": "validation", "detail": { "fieldErrors": { "monto": ["Number must be greater than 0"] } } }
```

| HTTP | `error` | Qué pasó | Qué haces |
|---|---|---|---|
| 400 | `validation` | Un campo falta o no es válido. Al listar enlaces con un filtro que no se entiende, viene además `parametro` con su nombre y `detail` es un texto | Revisa `detail` (y `parametro`) |
| 401 | `unauthorized` | Falta la llave, está mal escrita o fue revocada | Revisa `x-switch-key` |
| 403 | `comercio_suspendido` | Tu comercio está suspendido: no se pueden crear enlaces ni lotes (ni de prueba ni de producción) | Escríbenos para reactivarlo |
| 403 | `requiere_llave_live` | Con una llave de prueba intentaste crear o revocar una llave de producción | Usa una `sk_live_` → [Llaves](/developers/llaves-y-entornos) |
| 404 | `not_found` | Ese cobro no existe o no es de tu comercio | Revisa el `id` |
| 409 | p. ej. `item_duplicado` | Conflicto: en un lote, una `idempotency_key` de ítem ya usada | Revisa `detail` |
| 409 | `limite_webhooks` | Ya tienes 10 webhooks registrados | Borra uno que no uses → [Webhooks](/developers/webhooks-referencia) |
| 422 | `destino_bloqueado` | La URL del webhook apunta a una red interna | Usa una URL pública → [Webhooks](/developers/webhooks-referencia) |
| 400 / 422 / 503 | `split_…` | El pago dividido no está activo, el reparto no es válido, una cuenta no está aprobada en el portal o un control de seguridad la frena | → [Pago dividido](/developers/pago-dividido) |
| 409 | `idempotency_key_en_uso` | Esa `idempotency_key` ya la usaste con una llave del otro modo (prueba o producción) | Usa otra llave de idempotencia |
| 409 | `tope_diario_excedido` / `tope_acumulado_excedido` | Al pedir la clave de pago (página de pago, WhatsApp Flow o `POST /cobrar/token`): ese cobro pasaría el tope de lo que tu cuenta puede recibir hoy o en total. Trae `motivo` (el texto para tu cliente); con tu llave, además `tope` y `usado` (en Bs) y, si tu tope está en dólares, `topes_moneda`, `tope_usd` y `tasa_bcv` | Tu cliente no paga ahora; escríbenos si necesitas más tope → [Límites](/developers/limites-y-reglas) |
| 429 | — | Pasaste el límite de peticiones | Espera y reintenta → [Límites](/developers/limites-y-reglas) |
| 503 | `cierre_bancario` | En la página de pago, al pedir la clave entre las 11:45 p. m. y la 1:30 a. m. (hora de Venezuela): los bancos están en su cierre diario. Trae `motivo` (el texto para tu cliente) y `reintentar_en` (segundos hasta que termine) | Tu cliente paga después de la 1:30 a. m. con el mismo enlace → [Cierre diario](/developers/enlaces-de-pago#cierre-diario-de-los-bancos) |
| 5xx | — | Falla nuestra | Reintenta con la misma `idempotency_key` |

## Cuando el banco rechaza el pago

Eso no te llega como error de la API: tu cliente lo ve en la página de pago ("El banco no aprobó el pago") y puede intentarlo otra vez con una clave nueva. El cobro sigue `pendiente` hasta que lo pague o venza.

## Si tu comercio está suspendido

Mientras dure la suspensión:

- Crear enlaces (`POST /links`) o lotes (`POST /lotes`) responde `403` con `{ "error": "comercio_suspendido" }`.
- Un enlace que estaba `pendiente` no se puede empezar a pagar: tu cliente ve "Este comercio no está recibiendo pagos" y no se le cobra nada.
- Lo que ya se estaba pagando (`cobrando`, `procesando`, `revision`) termina normalmente, y el dinero de lo ya pagado se te sigue liquidando.
- Consultar y listar tus enlaces sigue funcionando.

## Reintentar sin duplicar

Si una creación falla por red o por un `5xx`, reintenta con la **misma** `idempotency_key`: si el primer intento sí llegó, recibes el mismo enlace en vez de uno nuevo.

```json
{ "monto": 150, "concepto": "Pedido #1024", "idempotency_key": "pedido-1024" }
```
