# Password reset

Password reset is a two-step flow: `forgot-password` emails the customer a reset link, `reset-password` consumes the token from that link. Both require the `customers:write` scope and neither requires `X-Customer-Token`. Both carry the extra credential-endpoint rate limit of 10 requests per minute per IP.

Reset tokens are single-use, stored hashed (SHA-256), and expire 60 minutes after they are issued. The reset link points at your store's configured storefront URL in the format `{storefront_url}/account/reset?token=...&email=...`; your storefront page at that path should read both query parameters and submit them to `reset-password`. If the store has no `storefront_url` configured, no email is sent (the endpoint still returns 202).

## POST /v1/api/customers/forgot-password

Request a password reset email. Always returns 202 with the same body whether or not an account with that email exists, so the endpoint cannot be used to enumerate accounts.

### Body parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | Yes | Valid email address. Lowercased server-side before lookup. |

```bash title="Request"
curl -X POST https://api.borkol.com/v1/api/customers/forgot-password \
  -H "Authorization: Bearer {api_key}" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com"}'
```

Status: `202 Accepted`.

```json title="Response"
{
  "message": "If the account exists, a reset link has been sent."
}
```

### Errors

- `422` when `email` is missing or not a valid email address.
- `429` when the 10 requests per minute per IP limit is exceeded.

## POST /v1/api/customers/reset-password

Complete a password reset with the token from the emailed link. On success this sets the new password, marks the account non-guest, sets `email_verified_at` if it was unset, and revokes all of the customer's session tokens (every device is logged out). An invalid or expired token leaves the account untouched.

### Body parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | Yes | Valid email address. Must match the account the token was issued for. |
| `token` | string | Yes | The plain token from the reset link's `token` query parameter. |
| `password` | string | Yes | The new password. Minimum 8 characters. |

```bash title="Request"
curl -X POST https://api.borkol.com/v1/api/customers/reset-password \
  -H "Authorization: Bearer {api_key}" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com","token":"kJ8s...64-char-token...Qw2","password":"new-s3cret-pass"}'
```

Status: `200 OK`.

```json title="Response"
{
  "message": "Password updated."
}
```

### Errors

- `422` with `errors.token` `["This reset link is invalid or expired."]` for an unknown email, a wrong token, an already-used token, or a token older than 60 minutes.
- `422` for field validation failures (missing fields, password shorter than 8 characters).
- `429` when the 10 requests per minute per IP limit is exceeded.
