> ## Documentation Index
> Fetch the complete documentation index at: https://developers.flowestate.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Errores

> Status codes HTTP, códigos de error que puedes pattern-matchar, y la forma de cada response de error.

Todo error tiene una forma JSON consistente:

```json theme={null}
{
  "error": {
    "message": "Explicación legible para humanos, a veces localizada al idioma de la organización.",
    "code": "CODIGO_PARA_MAQUINA"
  }
}
```

El status HTTP y el `error.code` siempre son consistentes. Haz switch sobre `code`, muestra `message` al usuario final.

## Códigos

| HTTP  | `error.code`       | Significado                                                                                                        |
| ----- | ------------------ | ------------------------------------------------------------------------------------------------------------------ |
| `400` | `BAD_REQUEST`      | Error genérico del cliente.                                                                                        |
| `400` | `VALIDATION_ERROR` | El cuerpo o query falló validación. El `message` lista los campos problemáticos.                                   |
| `401` | `UNAUTHORIZED`     | Bearer ausente, mal formado, desconocido o expirado.                                                               |
| `403` | `FORBIDDEN`        | Autenticado pero sin permiso: scope faltante, límite del plan alcanzado, key inactiva, o regla de negocio violada. |
| `404` | `NOT_FOUND`        | El recurso no existe o pertenece a otra organización.                                                              |
| `429` | `BAD_REQUEST`      | Límite de tasa excedido. Reintenta tras `Retry-After` segundos. Ver [Límites de tasa](/es/rate-limits).            |
| `500` | `INTERNAL_ERROR`   | Falla inesperada del servidor. Es seguro reintentar de forma idempotente tras un breve backoff.                    |

## Errores de límite del plan

Los errores `FORBIDDEN` por límite de plan llevan un mensaje localizado como *"Has alcanzado el número máximo de leads de tu plan."* — muéstraselo al usuario final tal cual, ya que son ellos los que pueden actuar (subir plan o eliminar registros).

Estos vienen de los billing guards en:

* `POST /leads` — cuando se excede `maxLeads`.
* `POST /projects` — cuando se excede `maxProjects`.
* `POST /webhooks/subscriptions` — cuando se excede `maxWebhookEndpoints`.

## Errores de validación

Los mensajes `VALIDATION_ERROR` listan cada campo que falló en formato `path: razón`, separados por `; `:

```json theme={null}
{
  "error": {
    "message": "Validation error: email: Invalid email; phone: String must be at most 50 characters",
    "code": "VALIDATION_ERROR"
  }
}
```

Parsea el mensaje si necesitas mostrar errores a nivel de campo en tu propia UI, o muestra el string completo.

## Idempotencia y reintentos

* `5xx` y `429` son seguros para reintentar. Usa exponential backoff topado al valor de `Retry-After` cuando esté presente.
* `4xx` (excepto `429`) significa que el request en sí está mal. No reintentes sin cambiarlo.
* `POST /webhooks/subscriptions` es idempotente cuando pasas `external_id` — ver [Crear una suscripción](/es/api-reference/webhooks#crear-una-suscripcion).
* Otras escrituras no son idempotentes. Si reintentas un `POST /leads` a ciegas, vas a crear duplicados. Usa [Buscar un lead](/es/api-reference/leads#buscar-un-lead) primero para deduplicar.
