Update the identity settings
PATCH /v1/identity-settings · permission identity-settings:write
Updates the environment's username settings with a JSON merge patch (application/merge-patch+json, RFC 7396). If-Match is required: missing gives 428, a stale version gives 412. If the settings were never written the version is "0" and the first write creates the row. A patch that changes nothing writes nothing and keeps the version.
Request
| Field | Type | Required | Description |
|---|---|---|---|
If-Match |
header | yes | The ETag of the settings as last read ("0" if never written). Missing: 428; stale: 412. |
username_identifier |
string | no | required, optional or off. Cannot be null. |
username_min_length |
integer | no | 3-64, not greater than username_max_length. Cannot be null. |
username_max_length |
integer | no | 3-64, not less than username_min_length. Cannot be null. |
reserved_usernames |
string[] | null | no | At most 1000 names; replaces the whole list (RFC 7396 does not merge arrays). null or [] clears it. Each entry is normalized, duplicates are dropped and the list is stored sorted. |
verification_policy |
string | no | before_sign_in (default) or after_sign_in. after_sign_in stops the unverified-account cleanup. Cannot be null. |
unverified_account_ttl_days |
integer | no | 1-30 (default 7): days an unverified sign-up is kept in a before_sign_in environment before it is deleted. Cannot be null. |
The username settings apply to later writes only; existing users are never changed by them. The verification settings also act on existing sign-ups (see below).
Enforcement rules
off(default): a request that writes a username (POST /v1/users,PATCH /v1/users/{id}) fails with422and codeidentifier_type_disabled(pointer/username). Clearing an existing username stays allowed, and a user patch that does not touch the username is not checked again. Sign-in does not resolve accounts by username.optional: a username may be set.required: creating a user through the management API without a username fails with422(required), and a management patch cannot clear it. Asking for the username on the sign-up form is up to the hosted login; social and just-in-time creation never ask for it.- Length: a username shorter than
username_min_lengthor longer thanusername_max_lengthfails with422(invalid). - Reserved names: a username whose normalized form is in
reserved_usernamesfails with422and codeusername_reserved. An invalid list entry fails with422and pointer/reserved_usernames/<i>. - Existing users are not changed when the setting changes; the rules apply to later writes only.
Unverified-account cleanup
verification_policy and unverified_account_ttl_days control the automatic cleanup of sign-ups that were never verified. The cleanup only runs while the email address (or the phone number) is a required identifier, which is the default for email.
before_sign_in(default): a user created by sign-up cannot receive tokens before verifying the required identifier. A sign-up user who,unverified_account_ttl_daysdays (1-30, default 7) after signing up, still has no verified email address or phone number, has never received a token and has no social or enterprise (SAML/OIDC) identity is permanently deleted. The cleanup runs periodically (hourly by default).after_sign_in: users receive tokens before verifying (email_verified: false); the cleanup does not run and no user is deleted.- Never deleted: users created through the management API, import, SCIM, an invitation or just-in-time federation, blocked users and users whose deletion has already started. Only sign-ups created after the cleanup started in the environment are eligible.
- Deletion cannot be undone: the user is hard-deleted, a tombstone with reason
unverified_expiredis kept and theuser.deletedevent is published. - A change of policy or period takes effect at the next run. Lowering
unverified_account_ttl_daysmakes older unverified sign-ups eligible at once; switching fromafter_sign_inback tobefore_sign_indeletes expired unverified sign-ups at the next run.
Response
200 OK with the updated settings and the new ETag.
{
"username_identifier": "optional",
"username_min_length": 3,
"username_max_length": 32,
"reserved_usernames": ["admin", "root", "support"],
"verification_policy": "before_sign_in",
"unverified_account_ttl_days": 7,
"updated_at": "2026-10-05T09:30:00.123456Z"
}
Errors
| HTTP | code | When |
|---|---|---|
| 400 | unknown_field |
The patch contains an unknown or read-only field, or is not a JSON object (malformed_request). |
| 412 | precondition_failed |
If-Match does not match the current version. |
| 415 | unsupported_media_type |
The content type is not application/merge-patch+json. |
| 422 | validation_failed |
A value is invalid, min is greater than max, or a field that cannot be null was set to null (code: invalid). |
| 428 | precondition_required |
The If-Match header is missing. |
| 401 | unauthenticated |
The credential is missing, invalid or revoked. |
| 403 | insufficient_permissions |
The credential lacks the required permission. |
| 429 | rate_limited |
The rate limit was exceeded; retry after the Retry-After period. |
| 503 | service_unavailable |
A dependency is temporarily unavailable; retry after the Retry-After period. |
Example
curl -X PATCH https://api.eu.keenauth.com/v1/identity-settings \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/merge-patch+json" \
-H 'If-Match: "0"' \
-d '{"username_identifier":"optional","username_max_length":32,"reserved_usernames":["admin","root","support"]}'