
# Buscar usuarios

`POST /v1/users:search` · permiso `users:read`

Busca usuarios con filtros que contienen datos personales. Estos filtros solo se aceptan en el cuerpo de la solicitud, nunca en la cadena de consulta, porque las cadenas de consulta acaban en los registros de proxies y de clientes. Los filtros se combinan con AND y se requiere al menos un filtro de identidad. Las coincidencias son exactas; no se ofrecen búsquedas por prefijo ni por subcadena. Una búsqueda que coincide con demasiados usuarios falla con `search_too_broad`; restrinja los filtros.

## Solicitud

Los parámetros de paginación van en la cadena de consulta; no contienen datos personales.

| Parámetro | En | Obligatorio | Descripción |
|---|---|---|---|
| `limit` | consulta | no | Tamaño de página, de 1 a 100. Por defecto 20. |
| `after` | consulta | no | Cursor opaco obtenido de `list_metadata.after`. Excluyente con `before`. |
| `before` | consulta | no | Cursor opaco obtenido de `list_metadata.before`. Excluyente con `after`. |
| `order` | consulta | no | `asc` o `desc` según la fecha de creación. Por defecto `desc`. |

Campos del cuerpo:

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `email` | string | no | Dirección de correo electrónico exacta. |
| `phone` | string | no | Número de teléfono exacto en formato E.164. |
| `username` | string | no | Nombre de usuario exacto. |
| `email_domain` | string | no | Dominio de correo electrónico exacto. |
| `app_metadata`, `user_metadata` | object | no | Hasta 3 claves de primer nivel; cada clave debe igualar un valor escalar. |
| `status` | string | no | `active`, `blocked` o `pending_deletion`. |

Un cursor solo es válido con el mismo conjunto de filtros y el mismo orden para los que se emitió.

## Respuesta

`200 OK`. `data` contiene los usuarios de la página; `list_metadata.before` y `list_metadata.after` son cursores para la página anterior y la siguiente (`null` cuando no hay ninguna). No se devuelve un recuento total.

Los datos personales se enmascaran cuando la clave no tiene el permiso `users:read_pii`: `email` pasa a ser `a***@e***.com`, `phone_number` conserva solo sus últimos 2 dígitos (`+**********67`), `name`, `given_name`, `family_name`, `middle_name` y `nickname` pasan a ser iniciales (`A. L.`), `username` conserva solo su primer carácter (`a***`), `birthdate` pasa a ser `****-**-**` y `address` pasa a ser `{"redacted": true}`. `user_metadata` y `app_metadata` no se enmascaran. Una clave sin `users:read_pii` puede seguir buscando con filtros exactos de datos personales; los resultados aparecen enmascarados.

```json
{
  "data": [ {
    "id": "usr_0a1b2c3d4e5f6g7h8j9k0m1n2p",
    "kind": "regular",
    "status": "active",
    "external_id": null,
    "username": null,
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "email_verified": true,
    "phone_number": null,
    "phone_verified": false,
    "user_metadata": {},
    "app_metadata": {},
    "created_via": "admin_api",
    "created_at": "2026-01-15T09:30:00Z",
    "updated_at": "2026-01-15T09:30:00Z",
    "last_sign_in_at": null,
    "deletion_requested_at": null,
    "deletion_due_at": null
  } ],
  "list_metadata": { "before": null, "after": "<opaque cursor>" }
}
```

## Errores

Cada error es un cuerpo `application/problem+json` con un `code` estable.

| HTTP | `code` | Cuándo |
|---|---|---|
| 400 | `unknown_field`, `invalid_cursor` | El cuerpo tiene un campo no admitido (por ejemplo, un filtro por prefijo), o el cursor no coincide con la solicitud. |
| 415 | `unsupported_media_type` | `Content-Type` no es `application/json`. |
| 422 | `validation_failed`, `search_too_broad` | Un filtro no es válido, no se indicó ningún filtro de identidad o la búsqueda coincide con demasiados usuarios. |
| 401 | `unauthenticated` | Falta la clave de API, no es válida o ha sido revocada. |
| 403 | `insufficient_permissions` | La clave no tiene el permiso `users:read`. |
| 429 | `rate_limited` | Se superó el límite de frecuencia; respete `Retry-After`. |
| 503 | `service_unavailable` | Una dependencia no está disponible temporalmente; vuelva a intentarlo más tarde. |

## Ejemplo

```bash
curl -X POST "https://api.eu.keenauth.com/v1/users:search?limit=20" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "ada@example.com"}'
```

## Datos personales

Este endpoint contiene datos personales: perfil del usuario final. [Datos personales en las API de KeenAuth](/docs/policies/personal-data) describe qué se almacena, cuánto tiempo se conserva y cómo se elimina. No envíe categorías especiales de datos personales (salud, datos biométricos, religión, opiniones políticas, orientación sexual) en ningún campo.
