---
title: "Step 1 of invite acceptance — set password"
method: POST
path: "/accept-invite/start"
tags: ["Auth"]
---

# Step 1 of invite acceptance — set password

`POST /accept-invite/start`

## Request

- Base URL: `http://localhost:8000`
- URL: `http://localhost:8000/accept-invite/start`
- Auth: none declared

Step 1 of the two-step invite acceptance flow (Phase 1+2 of MFA
roadmap).

Validates the 7-day invite token, sets the user's password, and
decides which branch to return:

- **Park admin / super admin** (``admin`` or any ``sa_*`` role):
  returns ``kind="mfa_enrolment_required"`` with a 15-minute
  ``invite_enrolment_token``. The frontend takes that token to
  the MFA enrolment endpoints; ``users.is_verified`` flips when
  the first method activates.
- **Other invitees**: returns ``kind="session"`` with a full
  access token, exactly like the legacy single-shot endpoint.

The 7-day invite link itself remains valid until the user's
full setup completes — bailing after step 1 just means they
re-click the link and go through ``/accept-invite/start`` again
(idempotent password update).

## Headers

- `API-Version` '1'

## Request body

- InviteAcceptStartRequest: POST body for /accept-invite/start. Token-as-body rather than token-in-path so the same endpoint can be hit by both the new two-step UI and the legacy ``/accept-invite/{token}`` shim.
  - `token` string, required
  - `password` string, required

## Response `200`

Successful Response

- union
  - InviteAcceptedResponse: Returned by /accept-invite/start for non-admin invites — a full session token and the standard ``UserPublic`` payload. Backward-compatible with the legacy single-shot ``/accept-invite/{token}`` body so older clients keep working through the shim.
    - `id` integer, required
    - `username` string, email, required
    - `firstname` string, nullable
    - `lastname` string, nullable
    - `displayname` string, nullable
    - `phone` string, nullable
    - `register_date` string, date-time, required
    - `roles` unknown[]
      - unknown
    - `profile_pic` string, required
    - `access_token` string, nullable
    - `pending_email` string, nullable
    - `mfa_satisfied` boolean
    - `mfa_enrolled` boolean
    - `mfa_recovery` boolean
    - `mfa_access_required` boolean
    - `kind` 'session'
  - InviteEnrolmentRequiredResponse: Returned by /accept-invite/start for park-admin invites. The user has set their password but ``users.is_verified`` has *not* yet flipped — that happens when the embedded ``invite_enrolment_token`` is exchanged at any of the MFA enrolment endpoints (TOTP or WebAuthn) and a first method activates. The token is good for 15 minutes; the underlying 7-day invite link can be re-clicked to start a fresh attempt.
    - `kind` 'mfa_enrolment_required'
    - `invite_enrolment_token` string, required
    - `username` string, required
    - `firstname` string, nullable
    - `lastname` string, nullable
    - `mfa_methods` string[], required

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/totalparks/apis/total-parks-public-api.md) · [All operations](https://skmtc.dev/totalparks/apis/total-parks-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/totalparks/apis/total-parks-public-api/revisions/dcb4c822e2c6?raw)
