---
title: "Mint the key — only fires from a real human click, never a prefetch"
method: POST
path: "/v1/auth/verify/confirm"
tags: ["auth"]
---

# Mint the key — only fires from a real human click, never a prefetch

`POST /v1/auth/verify/confirm`

## Request

- Base URL: `http://localhost:8000`
- URL: `http://localhost:8000/v1/auth/verify/confirm`
- Auth: none required

Step 3 — the actual mint. Only reachable via GET /verify's confirm-page JS, triggered by a real button click; a scanner's automatic prefetch of the emailed link never reaches this endpoint, so it can't burn the token before the human sees it. `plaintext_key` is returned exactly once here and never again — nothing else in the API can retrieve it after this response.

## Request body

- VerifyConfirmRequest
  - `token` string, required: Magic-link token from the emailed verify URL

## Response `200`

Successful Response

- VerifyConfirmResult: Result of actually consuming a magic-link token (POST /v1/auth/verify/confirm). `status` drives which other fields are populated: - "minted": plaintext_key + email are set. The key is shown exactly once — no endpoint can ever retrieve it again after this response. - "already_issued": email + key_hint are set (plaintext_key is never re-shown). - "invalid" | "used" | "expired": no other fields are set.
  - `status` 'minted' | 'already_issued' | 'invalid' | 'used' | 'expired', required
  - `plaintext_key` string, nullable
  - `email` string, nullable
  - `key_id` string, nullable
  - `key_hint` string, nullable

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/scoopkit/apis/scoopkit-api.md) · [All operations](https://skmtc.dev/scoopkit/apis/scoopkit-api/llms.txt) · [OpenAPI document](https://skmtc.dev/scoopkit/apis/scoopkit-api/revisions/18068781261d?raw)
