
# 사용자 검색

`POST /v1/users:search` · 권한 `users:read`

개인 정보가 포함된 필터로 사용자를 검색합니다. 이 필터는 요청 본문에서만 허용되며, 쿼리 문자열에서는 사용할 수 없습니다. 쿼리 문자열은 프록시 및 클라이언트 로그에 남기 때문입니다. 필터는 AND로 결합되며, 최소 하나의 식별 필터가 필요합니다. 일치 방식은 정확 일치이며, 접두사 검색과 부분 문자열 검색은 제공하지 않습니다. 너무 많은 사용자와 일치하는 검색은 `search_too_broad`로 실패하므로 필터를 좁혀 주십시오.

## 요청

페이지네이션 매개변수는 쿼리 문자열에 넣습니다. 이 매개변수에는 개인 정보가 포함되지 않습니다.

| 매개변수 | 위치 | 필수 | 설명 |
|---|---|---|---|
| `limit` | query | 아니요 | 페이지 크기, 1~100. 기본값은 20입니다. |
| `after` | query | 아니요 | `list_metadata.after`에서 받은 불투명 커서입니다. `before`와 함께 사용할 수 없습니다. |
| `before` | query | 아니요 | `list_metadata.before`에서 받은 불투명 커서입니다. `after`와 함께 사용할 수 없습니다. |
| `order` | query | 아니요 | 생성 시각 기준 `asc` 또는 `desc`. 기본값은 `desc`입니다. |

본문 필드:

| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| `email` | string | 아니요 | 정확한 이메일 주소입니다. |
| `phone` | string | 아니요 | E.164 형식의 정확한 전화번호입니다. |
| `username` | string | 아니요 | 정확한 사용자 이름입니다. |
| `email_domain` | string | 아니요 | 정확한 이메일 도메인입니다. |
| `app_metadata`, `user_metadata` | object | 아니요 | 최상위 키는 최대 3개이며, 각 키는 스칼라 값과 정확히 일치해야 합니다. |
| `status` | string | 아니요 | `active`, `blocked` 또는 `pending_deletion`. |

커서는 발급된 것과 동일한 필터 집합 및 정렬 순서에서만 유효합니다.

## 응답

`200 OK`. `data`에는 현재 페이지의 사용자가 들어 있습니다. `list_metadata.before`와 `list_metadata.after`는 이전 페이지와 다음 페이지의 커서이며, 해당 페이지가 없으면 `null`입니다. 전체 개수는 반환되지 않습니다.

키에 `users:read_pii` 권한이 없으면 개인 정보가 마스킹됩니다. `email`은 `a***@e***.com`이 되고, `phone_number`는 마지막 2자리만 남깁니다(`+**********67`). `name`, `given_name`, `family_name`, `middle_name`, `nickname`은 이니셜(`A. L.`)로 표시됩니다. `username`은 첫 글자만 남깁니다(`a***`). `birthdate`는 `****-**-**`가 되고 `address`는 `{"redacted": true}`가 됩니다. `user_metadata`와 `app_metadata`는 마스킹되지 않습니다. `users:read_pii` 권한이 없는 키도 정확 일치 개인 정보 필터로 검색할 수 있으며, 결과는 마스킹되어 반환됩니다.

```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>" }
}
```

## 오류

모든 오류는 안정적인 `code`가 포함된 `application/problem+json` 본문으로 반환됩니다.

| HTTP | `code` | 발생 조건 |
|---|---|---|
| 400 | `unknown_field`, `invalid_cursor` | 본문에 지원되지 않는 필드(예: 접두사 필터)가 있거나, 커서가 요청과 일치하지 않습니다. |
| 415 | `unsupported_media_type` | `Content-Type`이 `application/json`이 아닙니다. |
| 422 | `validation_failed`, `search_too_broad` | 필터가 유효하지 않거나, 식별 필터가 없거나, 검색 결과가 너무 많은 사용자와 일치합니다. |
| 401 | `unauthenticated` | API 키가 없거나 유효하지 않거나 폐기되었습니다. |
| 403 | `insufficient_permissions` | 키에 `users:read` 권한이 없습니다. |
| 429 | `rate_limited` | 요청 한도를 초과했습니다. `Retry-After`를 따르십시오. |
| 503 | `service_unavailable` | 종속 서비스를 일시적으로 사용할 수 없습니다. 나중에 다시 시도하십시오. |

## 예제

```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"}'
```

## 개인 정보

이 엔드포인트는 개인 정보를 다룹니다. 최종 사용자 프로필이 포함됩니다. [KeenAuth API의 개인 정보](/docs/policies/personal-data)에서 저장되는 항목, 보관 기간, 삭제 방법을 확인할 수 있습니다. 어떤 필드에도 특수 범주의 개인 정보(건강, 생체 정보, 종교, 정치적 견해, 성적 指向)를 보내지 마십시오.
