Update own email
curl --request PUT \ --url http://localhost:9090/api/v1/account/email \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \Update the authenticated user’s email (marks as unverified). Requires the current password, checked before the address: a blank one is a 400 with error_code VALIDATION_ERROR, a wrong one a 400 with error_code AUTHENTICATION_FAILED that counts against the failure limit shared with the password and OTP changes. Submitting the address the account already has changes nothing, keeps it verified, and answers 200 with the user as stored.
A change clears any pending verification code, and any password reset link already
sent stops working, since it was mailed to the previous address. Verify the new
address with sendAccountEmailVerification and verifyAccountEmail.
When SMTP is enabled and the previous address was verified, it is sent a notice that the address was changed, in the user’s language, after the response. The notice does not name the new address, and one that cannot be sent does not fail the change.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Example generated
{ "currentPassword": "example"}Responses
Section titled “Responses”Email updated
object
object
“female”, “male” or “other”, or empty when unset
ISO 3166-1 alpha-2 country code (e.g. US, BR), or empty string.
Example generated
{ "user": { "id": 1, "createdAt": "2026-04-15T12:00:00Z", "updatedAt": "2026-04-15T12:00:00Z", "enabled": true, "subject": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "username": "example", "givenName": "example", "middleName": "example", "familyName": "example", "nickname": "example", "website": "example", "gender": "example", "emailVerified": true, "zoneInfoCountryName": "example", "zoneInfo": "example", "locale": "example", "birthDate": "2026-04-15T12:00:00Z", "phoneNumberCountryUniqueId": "example", "phoneNumberCountryCallingCode": "example", "phoneNumber": "example", "phoneNumberVerified": true, "addressLine1": "example", "addressLine2": "example", "addressLocality": "example", "addressRegion": "example", "addressPostalCode": "example", "addressCountry": "example", "otpEnabled": true }}Invalid request body or parameters
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}Headers
Section titled “Headers”Bearer challenge when token transport is malformed; ordinary validation errors omit it.
Missing or invalid bearer token
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}Headers
Section titled “Headers”Bearer challenge on token refusals. An operation may also return a handler-level 401 without this header.
The token is valid but does not authorise this request. Four checks answer here, and a caller distinguishes them by error_code.
INSUFFICIENT_SCOPE comes from the route’s authorisation middleware,
before the handler runs: an Admin operation needs one of the scopes
its route names, and an Account operation needs
authserver:manage-account.
USER_CONTEXT_REQUIRED comes from the same middleware on the Account operations, which also require the token to have been issued for a user: one obtained through the client credentials grant carries no auth_time claim and is refused here.
FORBIDDEN comes from the handler, on the account endpoints that resolve a resource by id and then check it belongs to the caller, so a valid token for the wrong user reaches this rather than a 404.
MANAGE_SCOPE_REQUIRED comes from the handler, on the Admin operations
the administrative policy guards. Only authserver:manage creates an
administrator, changes one, or changes what reaches one, so no
granular scope will ever be enough: the remedy is a token holding
authserver:manage, not requesting the route’s scope as for
INSUFFICIENT_SCOPE. An administrator is a user, group or client
holding any of the six administrative permissions (manage,
admin-read, manage-users, manage-clients, manage-settings,
browser-sessions), a user directly or through any of its groups,
the admin console’s own client whatever it holds, and a client
allowed to request the administrative scopes. A granular scope is
refused here when it:
- grants or revokes an administrative permission, directly or by moving a user into or out of a group that holds one, or deletes such a group;
- writes to an administrator user (profile, credentials, enabled, sessions, consents, attributes, memberships, permissions, deletion), an administrative group (settings, attributes, members, permissions, deletion), or an administrator client (settings, authentication, flows, redirect URIs, web origins, token settings, permissions, logo, deletion);
- switches whether a client may request the administrative scopes, on or off, on any client;
- reads an administrator client’s secret;
- changes the email or the audit-log settings;
- changes an administrative permission’s description.
Granular scopes still read administrators. The refusal is answered
after the request’s 400 and 404, writes nothing, carries
WWW-Authenticate: Bearer realm="goiabada", error="insufficient_scope", error_description="...", scope="authserver:manage", and leaves anadministrator_change_refusedaudit record.
Every operation this document secures declares a 403. The public
client logo endpoint, which carries security: [] and authorises
nothing, is the one that does not.
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}Headers
Section titled “Headers”Bearer challenge on scope and administrative-policy refusals; other forbidden responses omit it.
Resource not found
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}The email address was registered to another user between the duplicate check and the write. error_code is EMAIL_ALREADY_EXISTS. An address already taken when the request arrives is a 400 with error_code validator.email.already_registered. Or another request changed the account’s address or its verification after this one read it: error_code is CONCURRENT_UPDATE, nothing was saved and no notice was sent. Read the account again and retry.
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}Rate limit reached. Every limit on the account API is counted by the token’s user and applies whether or not the rate limiter (GOIABADA_AUTHSERVER_RATELIMITER_ENABLED) is on. error_code is TOO_MANY_REQUESTS and a Retry-After header carries the window length in seconds.
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}Headers
Section titled “Headers”Seconds to wait before retrying
The request failed inside the server, most often a storage error. error_code is INTERNAL_SERVER_ERROR: no detail about the failure, only the request id an operator can find the log line by, and retrying is reasonable. Key rotation’s 500 also answers KEY_SET_INCOMPLETE, which names its cause and no retry clears.
Admin/account API error envelope. Routing by HTTP status code: 4xx is a client-correctable failure (validation, not found, permission denied, rate limited); 5xx is a server-side problem. The body provides a stable error_code and an error_description for people to read. Protocol endpoints (/auth/token, /auth/authorize, /connect/register, /userinfo) use their RFC-defined error envelopes instead of this one.
object
Stable identifier for the failure. UPPER_SNAKE for legacy codes (e.g. VALIDATION_ERROR), dotted lowercase for catalog-keyed localized codes (e.g. validator.email.required).
A sentence for people to read: in the request’s language when error_code is a catalog key, in English otherwise. Route on error_code, not on this text.
Example generated
{ "error_code": "example", "error_description": "example"}