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

# Fundamentos

> Convenciones de paginación, filtros, IDs, caché, rate limit y errores de la API.

## Paginación por cursor

Los endpoints de listado usan paginación por cursor y retornan `data` y
`has_more`. El límite predeterminado es de 25 elementos y puede configurarse
entre 1 y 100.

```json theme={null}
{
  "data": [
    {
      "object": "segment",
      "id": "seg_ckxyz123",
      "name": "Clientes VIP"
    }
  ],
  "has_more": true
}
```

Para obtener la página siguiente, envía el `id` del último elemento como
`starting_after`:

```bash theme={null}
curl --get https://api.bevits.com/v1/segments \
  --header "Authorization: Bearer $BEVITS_API_KEY" \
  --data-urlencode "limit=25" \
  --data-urlencode "starting_after=seg_ckxyz123"
```

Continúa mientras `has_more` sea `true`. No reutilices el cursor de un tipo de
recurso en otro listado.

## IDs públicos

Los IDs son strings opacos con un prefijo que identifica el recurso.

| Prefijo | Recurso          |
| ------- | ---------------- |
| `org_`  | Organización     |
| `bak_`  | Clave API        |
| `cus_`  | Cliente          |
| `seg_`  | Segmento         |
| `pur_`  | Compra           |
| `tag_`  | Etiqueta         |
| `atr_`  | Atributo         |
| `flw_`  | Flow             |
| `emc_`  | Campaña de email |

Trata los IDs como strings. No elimines el prefijo ni intentes inferir su
contenido.

## Filtros y fechas

Los filtros se envían como parámetros de query. Las fechas usan ISO 8601 con
offset; las respuestas se normalizan a UTC.

```bash theme={null}
curl --get https://api.bevits.com/v1/customers \
  --header "Authorization: Bearer $BEVITS_API_KEY" \
  --data-urlencode "is_subscribed=true" \
  --data-urlencode "updated_since=2026-07-01T00:00:00Z"
```

Los campos sin valor se omiten de las respuestas en lugar de retornar `null`.
Los valores monetarios usan centavos, como `total_spent_in_cents: 15990`.

## Errores

Los errores nunca se retornan con status `200`. El campo `error.type` es estable
para automatizaciones; `message` es legible por humanos; y `request_id`
identifica la solicitud para soporte.

```json theme={null}
{
  "error": {
    "type": "validation_error",
    "message": "Invalid input: expected number, received NaN",
    "param": "limit",
    "request_id": "req_07f6cdc3c20249d6afcd90b4"
  }
}
```

| HTTP  | `error.type`           | Significado                                                       |
| ----- | ---------------------- | ----------------------------------------------------------------- |
| `400` | `invalid_request`      | Ruta, cursor o formato de solicitud inválido.                     |
| `401` | `authentication_error` | Clave API ausente, inválida, expirada o revocada.                 |
| `403` | `permission_denied`    | La credencial no tiene el permiso necesario.                      |
| `404` | `not_found`            | El recurso no existe o pertenece a otra organización.             |
| `409` | `conflict`             | La solicitud entra en conflicto con el estado actual del recurso. |
| `422` | `validation_error`     | Un parámetro o valor no superó la validación.                     |
| `429` | `rate_limited`         | Se superó el límite de solicitudes.                               |
| `500` | `internal_error`       | Ocurrió un error inesperado en el servidor.                       |

## Rate limit

El límite inicial es de **600 solicitudes por minuto, por clave API**. Las
respuestas autenticadas incluyen:

```http theme={null}
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 599
X-RateLimit-Reset: 2026-07-25T21:31:00.000Z
```

Al recibir `429`, espera el número de segundos indicado en `Retry-After` antes
de volver a intentarlo. Usa backoff con jitter en integraciones automatizadas.

## Caché condicional

Las respuestas de recursos incluyen un `ETag`. Envía ese valor en
`If-None-Match` para evitar descargar nuevamente contenido que no cambió:

```http theme={null}
If-None-Match: "v1-4ad31f5efb6b8f35"
```

Cuando el contenido es idéntico, la API responde `304 Not Modified` sin body.
