---
title: "Confirm the code mailed by the request route."
method: POST
path: "/v1/me/email-verification/confirm"
tags: ["auth"]
---

# Confirm the code mailed by the request route.

`POST /v1/me/email-verification/confirm`

## Request

- Base URL: `http://localhost:8080`
- URL: `http://localhost:8080/v1/me/email-verification/confirm`
- Auth: one of:
  - API key in cookie `dvt_session`
  - HTTP bearer

DVT-5182. Checks the 6-digit code against the caller's newest pending code (5 guesses
per code, 10 failed guesses per user per rolling 24 hours) and, on a match, stores the
address as the caller's verified email. Errors: 400 `email-verification-expired` (no
pending, unexpired code with guesses left; request a new one), 400
`email-verification-code-mismatch` (extension `attemptsRemaining`), 429
`email-verification-rate-limited` with `Retry-After`. Same guards as the request route.
When a confirm replaces a different verified address, a notice (without the new address) is
mailed to the previous one after the response is written, best-effort: a failed notice is
logged and audited, never retried, and does not fail the confirm.

## Request body

- object
  - `code` string, required: The 6-digit code from the email.

## Response `200`

The address is verified.

- object
  - `data` object, required
    - `verifiedEmail` string, required
    - `verifiedEmailAt` string, date-time, required
  - `meta` Meta, required: Response metadata.
    - `requestId` string, required: Correlates with the X-Request-Id header.
    - `total` integer: Item count, present on collection responses.
    - `nextCursor` string, nullable: Opaque keyset-pagination cursor, present on paginated responses (e.g. GET /v1/dashboards) when more rows exist beyond this page. Pass it back as the `cursor` query param to fetch the next page; absent or null on the last page.
    - `roleResolveDegraded` boolean: Snowflake mode only (DVT-2260), on GET /v1/dashboards: present and true when the caller's live Snowflake role resolution failed or was unavailable — role-shared dashboards may be missing from this page. Omitted (not merely false) whenever resolution succeeded or the role-share arm does not apply (off snowflake mode, an org admin/owner, or off the ingress listener).

## Other responses

- `400`: Malformed code, an expired or exhausted code (`email-verification-expired`), or a wrong code (`email-verification-code-mismatch`, with `attemptsRemaining`).
- `401`: Missing, invalid, or expired session.
- `403`: The caller's role does not permit this action.
- `404`: Resource does not exist.
- `415`: `Content-Type` is not `application/json`.
- `429`: Per-actor API rate limit exceeded (SEC-2). All authenticated `/v1` routes apply a per-actor fixed-window default tier; selected compute-heavy routes (connection tests, column describe, data export) apply an additional tighter tier. Auth endpoints apply a per-IP tier. Problem type: `https://docs.dvt.dev/errors/rate-limited`. Wait for the `Retry-After` response header value (seconds) before retrying.

---

[API](https://skmtc.dev/dvt/apis/dvt-rest-api.md) · [All operations](https://skmtc.dev/dvt/apis/dvt-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dvt/apis/dvt-rest-api/revisions/00016f504165?raw)
