---
title: "Onboarding Complete"
method: POST
path: "/users/onboarding/complete"
tags: ["users"]
---

# Onboarding Complete

`POST /users/onboarding/complete`

## Request

- Base URL: `https://api.projectindi.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.projectindi.com/users/onboarding/complete`
- Auth: none declared

Complete parent onboarding at the end of the tour. appMobile
``onboardingService.markComplete`` calls this - its direct write sent no
welcome email (#10039). appweb ``onboardingClient.completeOnboarding``
still makes the twin direct Supabase write and requests the email itself;
pointing it here is a separate change.

Parent-only, like the web twin: a ``clinician_profiles`` holder 409s -
clinicians complete through the clinic setup / claim flows, and the role is
deliberately not a parameter (their own JWT could never write it anyway;
see the module invariants). Flips ``onboarded``, derives the role
(``_derived_role`` - never over a set one), clears the flow marker, then
sends the idempotent welcome email best-effort. A send missed here (or by a
stale bundle that never calls this) is picked up by the worker's welcome
sweep; see ``src/mailer/welcome.py``.

Two things stay client-side by contract: the JWT claim refresh (appweb
``commitRoutingWrite`` / mobile ``refreshAuthClaims`` - the middleware
trusts the stale claims until then) and the ``onboarding_completed``
capture (consent-gated with the rest of the paywall funnel).

## Response `200`

Successful Response

- OnboardingCompleteResponse
  - `success` boolean, required

---

[API](https://skmtc.dev/projectindi/apis/indi-agent-api-first-principles.md) - [All operations](https://skmtc.dev/projectindi/apis/indi-agent-api-first-principles/llms.txt) - [OpenAPI document](https://skmtc.dev/projectindi/apis/indi-agent-api-first-principles/revisions/25a7813e21fd?raw)
