Email and password changes
Changing the email address or the password on an account takes several steps. Fluxer opens a ticket, emails a code, and every later step presents that ticket together with the codes and proofs it has collected. An account whose address the mail provider rejected uses bounced email recovery instead.
Every operation needs a non-bot user session. The email change routes admit a session with suspicious account state. Every password change route rejects that state with 403 ACCOUNT_SUSPICIOUS_ACTIVITY.
Ticket and code contract
Section titled “Ticket and code contract”A ticket identifier is a version 4 UUID. Fluxer issues it when the flow starts, and every later step sends it as a plain string of 1 to 256 characters. Each ticket belongs to one account, and a step presented by another account fails with INVALID_OR_EXPIRED_TICKET. A completed ticket rejects every further step with TICKET_ALREADY_COMPLETED. Starting a flow again mints a fresh ticket and leaves an outstanding one usable.
A verification code is eight characters drawn from the uppercase Latin alphabet and the decimal digits, written as two four-character groups separated by a hyphen. A code lives for 10 minutes from the moment it is sent. Fluxer trims a submitted value and the comparison is otherwise exact, so a value with any other stray character fails with INVALID_VERIFICATION_CODE.
Fluxer returns a proof, a version 4 UUID, from every step that establishes a fact about the ticket. The email change flow issues original_proof for the original address and requires it on Request new email and Verify new email. The password change flow issues verification_proof for the emailed code and requires it to complete the change.
An email token is a version 4 UUID standing for one verified new address. It lives 30 minutes, belongs to the account it was issued to, and is deleted once consumed. A token presented by another account fails with INVALID_EMAIL_TOKEN, and one past its lifetime is deleted and fails with EMAIL_TOKEN_EXPIRED.
Fluxer refuses a resend for 30 seconds after the previous send of the same code, and that refusal is HTTP 429 with a Retry-After computed from the exact moment the next send becomes available. It is independent of the route bucket and of the longer email-send controls.
A ticket failure uses the path ticket, a code failure code, and an address failure new_email or email. A proof failure uses original_proof or verification_proof, an email token failure uses email_token, and a password failure uses password or new_password. The account-level codes ACCESS_DENIED, ACCOUNT_SUSPICIOUS_ACTIVITY, SUDO_MODE_REQUIRED, and RATE_LIMITED arrive as the top-level code.
Email send controls
Section titled “Email send controls”Each send-bearing operation passes through its own route bucket and, separately, through a longer email-send control keyed by the account. Exhausting either produces HTTP 429 even when the other has room.
| Control | Allowance | Operations |
|---|---|---|
| Original address | 3 sends per 15 minutes | Start email change and Resend original email code |
| New address | 5 sends per 15 minutes | Request new email, Resend new email code, and both bounced recovery sends |
| Password change start | 3 sends per 15 minutes | Start password change |
| Password change resend | 3 sends per 15 minutes | Resend password change code |
Email change ticket states
Section titled “Email change ticket states”The email change ticket moves through three states. A step legal in one state is rejected in every other with the transition code named below.
| Current state | Operation | Next state |
|---|---|---|
| Pending original | Resend original email code | Pending original |
| Pending original | Verify original email | Pending new |
| Pending new | Request new email | Pending new |
| Pending new | Resend new email code | Pending new |
| Pending new | Verify new email | Completed |
A ticket created without original email verification starts in the pending-new state and receives its original_proof directly from Start email change. Requesting or verifying a new address while the ticket is still pending original fails with ORIGINAL_EMAIL_MUST_BE_VERIFIED_FIRST.
Verifying the original stage on a ticket that never required it fails with ORIGINAL_VERIFICATION_NOT_REQUIRED. Resending the original code fails with ORIGINAL_EMAIL_ALREADY_VERIFIED on a cleared ticket and on a ticket that never required the stage, so the response does not tell the two apart. Verifying the original address again on a cleared ticket returns the same original_proof unchanged.
Resending the new address code before an address has been requested fails with NO_NEW_EMAIL_REQUESTED. A pending-original ticket returns the same code.
Request new email and Resend new email code share one 30-second cooldown. Requesting a different address cannot bypass it.
Reaching the completed state issues an email token and leaves the account email unchanged. Apply email change writes the new address.
Email change start object
Section titled “Email change start object”The state of a freshly created email change ticket.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier every later step of this flow sends |
| require_original1 | boolean | Whether the original address needs verification before a new address can be requested |
| original_email2 | ?string | The address currently on the account, or null when the account has none |
| original_proof3 | ?string | The proof for the original address stage, or null while that stage is unverified |
| original_code_expires_at4 | ?ISO8601 timestamp | The moment the code sent to the original address expires, 10 minutes after it was sent |
| resend_available_at4 | ?ISO8601 timestamp | The earliest moment the original address code can be resent, 30 seconds after the last send |
1 True only when the account holds an email address and that address is verified
2 Recorded on the ticket at creation, so a later change to the account email does not move it. Request new email compares against this recorded value
3 Populated exactly when require_original is false. Request new email and Verify new email require it
4 Null whenever require_original is false
Example
Section titled “Example”{ "ticket": "6f1a4c9e-3d52-4a77-9b0e-2c8f5d41ab30", "require_original": true, "original_email": "old@example.com", "original_proof": null, "original_code_expires_at": "2026-03-04T18:10:00.000Z", "resend_available_at": "2026-03-04T18:00:30.000Z"}New email request object
Section titled “New email request object”The state of a ticket with a candidate address bound to it and a code in flight to that address.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| ticket1 | string | The identifier every later step of this flow sends |
| new_email2 | string | The address now bound to the ticket |
| new_code_expires_at | ISO8601 timestamp | The moment the code sent to the new address expires, 10 minutes after it was sent |
| resend_available_at3 | ?ISO8601 timestamp | The earliest moment the new address code can be resent, 30 seconds after the last send |
1 Echoes the ticket the request named, except on Request replacement email for bounced address, where it identifies the ticket that operation created
2 The trimmed form of the submitted address, which is what a later Verify new email writes
3 Always populated
Original email verification object
Section titled “Original email verification object”The proof that a ticket has cleared its original address stage.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| original_proof1 | string | The proof Request new email and Verify new email require |
1 Stable for the lifetime of the ticket. Verifying the original address again returns the same value
New email verification object
Section titled “New email verification object”The email token a completed email change ticket hands back.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| email_token1 | string | The token Apply email change consumes to write the address |
1 The token lives 30 minutes and stands for the exact address the ticket verified
Password change start object
Section titled “Password change start object”The state of a freshly created password change ticket.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier every later step of this flow sends |
| code_expires_at | ISO8601 timestamp | The moment the emailed code expires, 10 minutes after it was sent |
| resend_available_at1 | ?ISO8601 timestamp | The earliest moment the code can be resent, 30 seconds after the last send |
1 Always populated
Password verification object
Section titled “Password verification object”The proof that the emailed code was accepted.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| verification_proof1 | string | The proof Complete password change consumes |
1 Stable for the lifetime of the ticket. Verifying the same code again returns the same value
Password change completion object
Section titled “Password change completion object”The replacement session Complete password change hands back after the password is written.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| token1 | string | The authentication token for the replacement session |
| auth_session_id_hash | string | The base64url-encoded hash of the replacement authentication session |
1 The same operation destroys the token the client authenticated with, so adopt this value before issuing another request
Start email change
Section titled “Start email change”POST/v1/users/@me/email-change/startCreates an email change ticket. Returns an email change start object on success.
Only an account that holds an email address or is unclaimed can start an email change. Every other account fails with MUST_HAVE_EMAIL_TO_CHANGE_IT.
Original address verification applies only when the account holds a verified email address. A bounce clears the verified state. An account that has done nothing since the bounce gets a ticket that skips the original stage. Apply email change marks the address verified again without clearing the bounced marker, so an account that has applied a change since the bounce gets a ticket that does require the stage.
Sending an original address code consumes the original address control.
JSON body
Section titled “JSON body”The body can be omitted, and any supplied body is an object with no fields. Fluxer strips unknown keys before it handles the request.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | email change start object | The ticket was created |
Side effects
Section titled “Side effects”When original address verification applies, Fluxer creates the ticket in the pending-original state and sends one verification email to the account’s current address. A ticket that skips the stage is created pending-new with its original_proof already issued. No account field changes.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:email_change:start bucket.
Resend original email code
Section titled “Resend original email code”POST/v1/users/@me/email-change/resend-originalSends a fresh verification code to the account’s original address for an active ticket. Returns 204 with an empty body.
A ticket that is no longer pending-original fails with ORIGINAL_EMAIL_ALREADY_VERIFIED. A ticket recording no original address fails with NO_ORIGINAL_EMAIL_ON_RECORD.
The send consumes the original address control, and the ticket enforces its own 30-second cooldown.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Start email change (1-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 204 | empty | A replacement original address code was sent |
Side effects
Section titled “Side effects”Fluxer replaces the ticket’s original address code, send time, and code expiry, which invalidates the previous code. One verification email goes to the original address.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:email_change:resend_original bucket.
Verify original email
Section titled “Verify original email”POST/v1/users/@me/email-change/verify-originalVerifies the original address stage and advances the ticket to pending-new. Returns an original email verification object on success.
Running the operation against a ticket that already cleared the stage returns the same proof and changes nothing. A ticket that never required the stage fails with ORIGINAL_VERIFICATION_NOT_REQUIRED. A ticket with no issued code fails with VERIFICATION_CODE_NOT_ISSUED, a code past its 10-minute lifetime with VERIFICATION_CODE_EXPIRED, and a mismatch with INVALID_VERIFICATION_CODE.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Start email change (1-256 characters) |
| code | string | The code sent to the original address (1-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | original email verification object | The original address is verified |
Rate limit
Section titled “Rate limit”20 requests per minute for each authenticated user, on the user:email_change:verify_original bucket.
Request new email
Section titled “Request new email”POST/v1/users/@me/email-change/request-newBinds a new address to an active ticket and sends it a verification code. Returns a new email request object on success.
A ticket that has not cleared original address verification fails with ORIGINAL_EMAIL_MUST_BE_VERIFIED_FIRST. An original_proof that does not match the ticket fails with INVALID_PROOF_TOKEN.
Fluxer trims the address and then checks it in order. An empty address fails with EMAIL_IS_REQUIRED, an address equal to the ticket’s recorded original with NEW_EMAIL_MUST_BE_DIFFERENT, a domain that fails DNS eligibility with INVALID_EMAIL_ADDRESS, and an address another account already owns with EMAIL_ALREADY_IN_USE. Ownership is checked again when the resulting email token is applied, so passing here reserves nothing. Calling the operation again with a different address replaces the pending address on the same ticket.
The send consumes the new address control, and the ticket enforces its own 30-second cooldown.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Start email change (1-256 characters) |
| new_email1 | string | The address to bind to the ticket (1-254 characters) |
| original_proof | string | The proof issued by Start email change or Verify original email (1-256 characters) |
| new_password?2 | string | The password to check against the breached-password corpus (8-256 characters) |
1 A syntactically invalid address fails with INVALID_EMAIL_FORMAT, one outside the length bound with EMAIL_LENGTH_INVALID, and a local part outside the permitted ASCII set with INVALID_EMAIL_LOCAL_PART
2 The value is only checked against the breached-password corpus, which reports a match as PASSWORD_IS_TOO_COMMON. Nothing on this page writes it
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | new email request object | The address was bound and a code was sent |
Side effects
Section titled “Side effects”The ticket stores the requested address, a fresh code, its send time, and its expiry, and stays pending-new. One verification email goes to the requested address. The account’s own email address is untouched at this stage.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:email_change:request_new bucket.
Resend new email code
Section titled “Resend new email code”POST/v1/users/@me/email-change/resend-newSends a fresh verification code to the address already bound to an active ticket. Returns 204 with an empty body.
A ticket with no requested address fails with NO_NEW_EMAIL_REQUESTED.
The send consumes the new address control, and the ticket enforces its own 30-second cooldown.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Start email change (1-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 204 | empty | A replacement new address code was sent |
Side effects
Section titled “Side effects”Fluxer replaces the ticket’s new address code, send time, and code expiry, which invalidates the previous code. One verification email goes to the requested address.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:email_change:resend_new bucket.
Verify new email
Section titled “Verify new email”POST/v1/users/@me/email-change/verify-newVerifies the requested address and completes the ticket. Returns a new email verification object on success.
An original_proof that does not match the ticket fails with INVALID_PROOF_TOKEN. A ticket with no requested address or no issued code fails with VERIFICATION_CODE_NOT_ISSUED, a code past its 10-minute lifetime with VERIFICATION_CODE_EXPIRED, and a mismatch with INVALID_VERIFICATION_CODE.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Start email change (1-256 characters) |
| code | string | The code sent to the new address (1-256 characters) |
| original_proof | string | The proof issued by Start email change or Verify original email (1-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | new email verification object | The new address is verified |
Side effects
Section titled “Side effects”The ticket moves to the completed state and a 30-minute email token is issued for the verified address. The account’s email address is still unchanged.
Rate limit
Section titled “Rate limit”20 requests per minute for each authenticated user, on the user:email_change:verify_new bucket.
Apply email change
Section titled “Apply email change”POST/v1/users/@me/email-change/applyConsumes an email token and writes its address to the account. Returns the updated user object on success. Emits a User Update Gateway event.
A claimed account proves sudo mode before the route examines the token. The route accepts suspicious account state.
A token that belongs to another account fails with INVALID_EMAIL_TOKEN, and one past its 30-minute lifetime fails with EMAIL_TOKEN_EXPIRED. An expired token is deleted when rejected. Fluxer checks the address against existing account ownership again here, and an address another account has taken since fails with EMAIL_ALREADY_IN_USE without consuming the token.
An unclaimed account is exempt from sudo mode and applies the change with its session alone.
Modify current user accepts the same token alongside an unrelated profile edit. The token is single use, so a retry after success fails with INVALID_EMAIL_TOKEN.
JSON body
Section titled “JSON body”The body extends the sudo verification object with email_token, and the five sudo fields it merges in are repeated below. An existing sudo proof travels in the X-Fluxer-Sudo-Mode-JWT request header.
| Field | Type | Description |
|---|---|---|
| email_token | string | The token returned by Verify new email (1-256 characters) |
| password?1 | string | The account password (8-256 characters) |
| mfa_method?2 | string | The sudo MFA method, either totp or webauthn |
| mfa_code?3 | string | The sudo authenticator code or an unconsumed backup code (1-32 characters) |
| webauthn_response?4 | WebAuthn assertion object | The assertion produced for the supplied challenge |
| webauthn_challenge?4 | string | The challenge returned by create sudo WebAuthn authentication options (1-256 characters) |
1 Considered only while the account holds no MFA authenticator, and ignored once TOTP or a WebAuthn credential exists
2 Required when the account holds any MFA authenticator, unless the request already presents an accepted sudo proof
3 Required when mfa_method is totp. The value is a current authenticator code or an unconsumed backup code
4 Both fields are required together when mfa_method is webauthn
The body has no profile field and no new_password field, and Fluxer strips unknown keys before it handles the request.
An unclaimed account that also wants a first password makes a single Modify current user call with email_token and new_password.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | user object | The verified email change was applied |
| 403 | error response | Sudo mode was not proven and the request returns SUDO_MODE_REQUIRED with the sudo mode methods object |
The 200 has X-Fluxer-Sudo-Mode-JWT when sudo verification issued a proof.
Side effects
Section titled “Side effects”Fluxer replaces the account email, marks it verified, and removes every email-clearable suspicious activity flag, which can empty required_actions and restore ordinary access. Fluxer evaluates the new address against the instance contact policy separately, and that check can add suspicious activity flags. The bounced marker is not cleared, so an account that has it recovers through bounced email recovery.
For an ordinary change from an existing address, Fluxer sends a revert email to the original address so its holder can use Revert an email change. Fluxer deletes the email token, records the contact change in the account’s contact change log, and emits User Update. No public member field changes, so no Guild Member Update follows.
Rate limit
Section titled “Rate limit”20 requests per minute for each authenticated user, on the user:email_change:apply bucket.
Bounced email recovery
Section titled “Bounced email recovery”An account whose stored address the mail provider rejected has the bounced marker, reported as email_bounced on the user object. The bounce also clears the verified email state and imposes a required action. The three operations below bind a replacement address and finish without the sudo-gated apply step.
Every one of them requires the bounced marker. An account without it is rejected with 403 ACCESS_DENIED, and an account with no address at all is rejected with MUST_HAVE_EMAIL_TO_CHANGE_IT.
The flow also requires the account to hold no verified address, which is the state a bounce leaves. Apply email change marks an address verified without clearing the bounced marker. An account that took the ordinary flow after its bounce has both states, gets ORIGINAL_EMAIL_MUST_BE_VERIFIED_FIRST here, and changes its address through the ordinary flow.
Ticket and code contract governs its codes, cooldown, and new address send control. The verification step writes the address and clears the marker in one call.
Request replacement email for bounced address
Section titled “Request replacement email for bounced address”POST/v1/users/@me/email-change/bounced/request-newStarts the recovery flow. Returns a new email request object on success.
This operation creates a ticket and binds the replacement address in the same call. The route accepts suspicious account state. Fluxer checks the address exactly as Request new email checks it, so it passes DNS eligibility, belongs to no other account, and differs from the bounced address.
The send consumes the new address control.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| new_email | string | The address to replace the bounced one (1-254 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | new email request object | The replacement address was bound and a code was sent |
| 403 | error response | The account is not marked bounced and the request returns ACCESS_DENIED |
Side effects
Section titled “Side effects”A ticket is created pending-new with the replacement address bound to it, and one verification email goes to that address. No account field changes. Retain the returned ticket, because the two remaining steps take no other identifier.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:email_change:bounced:request_new bucket.
Resend replacement email code
Section titled “Resend replacement email code”POST/v1/users/@me/email-change/bounced/resend-newSends a fresh verification code to the replacement address bound to an active recovery ticket. Returns 204 with an empty body.
A ticket with no replacement address fails with NO_NEW_EMAIL_REQUESTED.
The send consumes the new address control, and the ticket enforces its own 30-second cooldown.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Request replacement email for bounced address (1-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 204 | empty | A replacement code was sent |
| 403 | error response | The account is not marked bounced and the request returns ACCESS_DENIED |
Side effects
Section titled “Side effects”Fluxer replaces the ticket’s code, send time, and code expiry, which invalidates the previous code. One verification email goes to the replacement address.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:email_change:bounced:resend_new bucket.
Verify replacement email for bounced address
Section titled “Verify replacement email for bounced address”POST/v1/users/@me/email-change/bounced/verify-newVerifies the replacement address and writes it to the account in the same call. Returns the updated user object on success. Emits a User Update Gateway event.
No sudo verification and no email token step applies.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Request replacement email for bounced address (1-256 characters) |
| code | string | The code sent to the replacement address (1-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | user object | The replacement address was verified and written |
| 403 | error response | The account is not marked bounced and the request returns ACCESS_DENIED |
Side effects
Section titled “Side effects”Fluxer replaces the account email, marks it verified, clears the bounced marker, and removes every email-clearable suspicious activity flag, which can empty required_actions and restore ordinary access. It marks the ticket completed and deletes its email token immediately. The contact change is recorded in the account’s contact change log.
No revert email is sent.
Rate limit
Section titled “Rate limit”20 requests per minute for each authenticated user, on the user:email_change:bounced:verify_new bucket.
Start password change
Section titled “Start password change”POST/v1/users/@me/password-change/startCreates a password change ticket and sends a verification code to the account email. Returns a password change start object on success.
An account holding no email address fails with MUST_HAVE_EMAIL_TO_CHANGE_IT.
The send consumes the password change start control.
JSON body
Section titled “JSON body”The body can be omitted, and any supplied body is an object with no fields. Fluxer strips unknown keys before it handles the request.
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | password change start object | The ticket was created and a code was sent |
Side effects
Section titled “Side effects”A ticket is created in its pending state and one verification email goes to the account address. No account field changes.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:password_change:start bucket.
Resend password change code
Section titled “Resend password change code”POST/v1/users/@me/password-change/resendSends a fresh verification code for an active password change ticket. Requires the account to still hold an email address. Returns 204 with an empty body.
The send consumes the password change resend control, and the ticket enforces its own 30-second cooldown.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Start password change (1-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 204 | empty | A replacement code was sent |
Side effects
Section titled “Side effects”Fluxer replaces the ticket’s code, send time, and code expiry, which invalidates the previous code. One verification email goes to the account address.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:password_change:resend bucket.
Verify password change code
Section titled “Verify password change code”POST/v1/users/@me/password-change/verifyVerifies the emailed code. Returns a password verification object on success.
Running the operation against an already verified ticket returns the same proof. A ticket with no issued code fails with VERIFICATION_CODE_NOT_ISSUED, a code past its 10-minute lifetime with VERIFICATION_CODE_EXPIRED, and a mismatch with INVALID_VERIFICATION_CODE.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Start password change (1-256 characters) |
| code | string | The code sent to the account address (1-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | password verification object | The code was accepted |
Side effects
Section titled “Side effects”The ticket moves to its verified state and stores a verification proof. The account password is still unchanged.
Rate limit
Section titled “Rate limit”20 requests per minute for each authenticated user, on the user:password_change:verify bucket.
Complete password change
Section titled “Complete password change”POST/v1/users/@me/password-change/completeConsumes a verified ticket and replaces the account password. Returns a password change completion object on success. Emits an Auth Session Change Gateway event with the replacement token.
No sudo verification applies. A ticket outside its verified state or a proof that does not match fails with INVALID_OR_EXPIRED_TICKET or INVALID_PROOF_TOKEN. A replacement password in the public breached-password corpus is rejected with PASSWORD_IS_TOO_COMMON. The ticket is marked completed once the password is written, so a retry fails with TICKET_ALREADY_COMPLETED.
JSON body
Section titled “JSON body”| Field | Type | Description |
|---|---|---|
| ticket | string | The identifier returned by Start password change (1-256 characters) |
| verification_proof | string | The proof issued by Verify password change code (1-256 characters) |
| new_password | string | The password to write to the account (8-256 characters) |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | password change completion object | The password was replaced |
Side effects
Section titled “Side effects”The password and its change timestamp are replaced and the ticket is marked completed. Every outstanding password reset token is deleted. Fluxer deletes and terminates every other authentication session on the Gateway first, then emits Auth Session Change, then deletes and terminates the caller’s own session. The returned replacement is then the account’s only session. OAuth2 access tokens and refresh tokens are not revoked.
Rate limit
Section titled “Rate limit”10 requests per minute for each authenticated user, on the user:password_change:complete bucket.