# Start changing your email address

> The users.email_change.start operation: POST /api/v1/users/me/email_change/start in the REST API and the users_email_change_start tool in the MCP server.

Starts moving your Ownrecord account to a new email address: a six-digit code goes to the new address, and
`users.email_change.confirm` with that code makes the change. The code works for 10 minutes and allows 5
guesses. Starting again replaces the open change and its code.

The answer is the same whether or not the new address already has an Ownrecord account, so nobody can use this
to find out which addresses have one. An address that already has an account gets a notice instead of a code,
and `users.email_change.confirm` answers `email_taken` only after a code proved the address is yours.

Limits: 3 starts an hour per account and 5 a day per new address (`rate_limited`). Refused for platform staff,
whose addresses follow the staff domains and their identity provider (`email_change_not_allowed`), and for
disposable addresses. If you sign in with Google or Microsoft, that keeps working after the change.

**Who can call it:** the signed-in user, for their own account, in the console, with a sign-in in the last 15
minutes.

## At a glance

- **REST:** `POST /api/v1/users/me/email_change/start`
- **MCP tool:** `users_email_change_start`
- **Operation ID:** `users.email_change.start`
- **Scope:** Platform
- **Permission:** `account:write`
- **Risk tier:** `security`
- **Dry run:** Not supported
- **Idempotency:** `Idempotency-Key` required
- **Modes:** Test and live
- **Authentication:** API key with the `account:write` scope
- **Fresh sign-in:** In the console, a sign-in within the last 15 minutes
- **Since:** M13

## Request

### Body

A JSON object (`Content-Type: application/json`):

| Field      | Type   | Required | Description                                             |
| ---------- | ------ | -------- | ------------------------------------------------------- |
| `newEmail` | string | Yes      | The address to move your account to. A code goes there. |

## Response

`200 OK` with a JSON object:

| Field       | Type                     | Description                                                          |
| ----------- | ------------------------ | -------------------------------------------------------------------- |
| `object`    | `"email_change_request"` |                                                                      |
| `id`        | `emc_…` ID               |                                                                      |
| `email`     | string                   | The new address, normalised (lower case).                            |
| `expiresAt` | date-time                | When the code stops working (10 minutes after the start).            |
| `message`   | string                   | What to do next. The same whether or not the address has an account. |

## Examples

### Move my account to a new address

```http
POST /api/v1/users/me/email_change/start
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "newEmail": "ana.novak@example.com"
}
```

Response (`200`):

```json
{
  "object": "email_change_request",
  "id": "emc_01m4tx5nj8emwbyf7y9vcf47xg",
  "email": "ana.novak@example.com",
  "expiresAt": "2026-11-04T09:10:00.000Z",
  "message": "We've sent an email to ana.novak@example.com. Enter the code from it within 10 minutes to confirm the address."
}
```

## Errors

| Code                                                                                                   | HTTP status | When                                                                     | What to do                                                                                                        |
| ------------------------------------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| [`email_invalid`](https://ownrecord.io/docs/reference/errors.md#email_invalid)                         | 400         | `newEmail` isn't an address that can receive a code.                     | Check the address and try again.                                                                                  |
| [`email_change_same_address`](https://ownrecord.io/docs/reference/errors.md#email_change_same_address) | 400         | `newEmail` is already your address.                                      | Enter the new address you want to use.                                                                            |
| [`email_domain_blocked`](https://ownrecord.io/docs/reference/errors.md#email_domain_blocked)           | 400         | `newEmail` is a disposable address.                                      | Sign up with a permanent address, for example your work email.                                                    |
| [`email_change_not_allowed`](https://ownrecord.io/docs/reference/errors.md#email_change_not_allowed)   | 403         | You're platform staff.                                                   | Staff addresses follow the staff domains and your Google or Microsoft account. Ask a platform admin to change it. |
| [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited)                           | 429         | 3 starts in the last hour for your account, or 5 today for this address. | Wait for `retry_after_ms` and retry with backoff.                                                                 |
| [`email_change_unavailable`](https://ownrecord.io/docs/reference/errors.md#email_change_unavailable)   | 500         | The platform isn't set up yet.                                           | Try again later. If it persists, contact support with the request ID.                                             |
| [`fresh_auth_required`](https://ownrecord.io/docs/reference/errors.md#fresh_auth_required)             | 403         | Your last sign-in is older than 15 minutes: sign in again first.         | Sign in again, then repeat the action within 15 minutes.                                                          |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)                 | 403         | The caller isn't a person signed in to the console.                      | Ask an organization owner or admin for a role or scope that allows this action.                                   |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed), [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`invalid_json`](https://ownrecord.io/docs/reference/errors.md#invalid_json), [`unsupported_media_type`](https://ownrecord.io/docs/reference/errors.md#unsupported_media_type), [`authentication_required`](https://ownrecord.io/docs/reference/errors.md#authentication_required), [`api_key_invalid`](https://ownrecord.io/docs/reference/errors.md#api_key_invalid), [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found), [`idempotency_key_required`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_required), [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://ownrecord.io/docs/reference/errors.md#idempotency_in_progress), [`dry_run_not_supported`](https://ownrecord.io/docs/reference/errors.md#dry_run_not_supported), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
