
# 사용자 생성

`POST /v1/users` · 권한 `users:write`

API 키의 환경에 사용자를 생성합니다. 사용자는 해당 환경에만 속하며, 두 환경에 같은 이메일 주소가 있으면 서로 다른 두 사용자로 취급됩니다. 고유 값(`email`, `phone_number`, `username`, `external_id`)은 환경별로 확인합니다. 재시도를 안전하게 처리하려면 `Idempotency-Key` 헤더를 보내십시오.

## 요청

본문은 JSON 객체입니다. 스키마에 없는 필드가 있으면 `unknown_field` 오류와 함께 거부됩니다.

| 필드 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
| `email` | string | 아니요* | 기본 이메일 주소입니다. |
| `email_verified` | boolean | 아니요 | 이메일 주소를 인증됨으로 표시합니다. 기본값은 `false`입니다. |
| `phone_number` | string | 아니요* | E.164 형식의 기본 전화번호입니다. |
| `phone_verified` | boolean | 아니요 | 전화번호를 인증됨으로 표시합니다. 기본값은 `false`입니다. |
| `phone_country_code` | string | 아니요 | ISO 3166-1 alpha-2 코드입니다. 비어 있으면 전화번호 접두사에서 도출합니다. |
| `username` | string | 아니요* | 3~64자입니다. 환경 내에서 고유해야 합니다. |
| `external_id` | string | 아니요 | 고객사가 관리하는 식별자이며, 1~255자입니다. 환경 내에서 고유해야 합니다. |
| `name`, `given_name`, `family_name`, `middle_name`, `nickname` | string | 아니요 | 프로필 이름입니다. |
| `picture`, `website`, `profile_url` | string | 아니요 | `https://` URL이며, 최대 2048자입니다. |
| `locale`, `zoneinfo`, `gender`, `birthdate` | string | 아니요 | 프로필 속성입니다. `birthdate`는 `YYYY-MM-DD` 형식입니다. |
| `address` | object | 아니요 | OIDC `address` 객체이며, 최대 2048바이트입니다. |
| `user_metadata`, `app_metadata` | object | 아니요 | 자유 형식 JSON 객체이며, 최대 16 KiB, 깊이 5, 최상위 키 100개까지 허용됩니다. |

\* `email`, `phone_number`, `username` 중 하나 이상이 필요합니다.

## 응답

`201 Created`를 반환합니다. 본문은 사용자 객체입니다. `ETag` 헤더에는 사용자 버전이 담깁니다.

API 키에 `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`는 마스킹되지 않습니다.

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

## 오류

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

| HTTP | `code` | 발생 조건 |
|---|---|---|
| 400 | `malformed_request`, `unknown_field` | 본문이 유효한 JSON이 아니거나 스키마에 없는 필드가 있습니다. |
| 409 | `conflict` | 값이 이미 사용 중입니다. `errors[]`에 필드와 사유(`email_taken`, `phone_taken`, `username_taken`, `external_id_taken`)가 표시됩니다. |
| 415 | `unsupported_media_type` | `Content-Type`이 `application/json`이 아닙니다. |
| 422 | `validation_failed` | 값이 유효하지 않습니다. `errors[].pointer`에 해당 필드가 표시됩니다. |
| 401 | `unauthenticated` | API 키가 없거나 유효하지 않거나 폐기되었습니다. |
| 403 | `insufficient_permissions` | API 키에 `users:write` 권한이 없습니다. |
| 429 | `rate_limited` | 요청 한도를 초과했습니다. `Retry-After`를 따르십시오. |
| 503 | `service_unavailable` | 종속 서비스를 일시적으로 사용할 수 없습니다. 나중에 다시 시도하십시오. |

## 예시

```bash
curl -X POST https://api.eu.keenauth.com/v1/users \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"email": "ada@example.com", "email_verified": true, "name": "Ada Lovelace"}'
```

## 개인정보

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