---
title: "Complete Onboarding"
method: POST
path: "/api/auth/onboarding/complete"
tags: ["Auth"]
---

# Complete Onboarding

`POST /api/auth/onboarding/complete`

## Request

- Base URL: `https://api.earmarkiq.app` (the document declares no server; this is the origin it was published from)
- URL: `https://api.earmarkiq.app/api/auth/onboarding/complete`
- Auth: HTTP bearer

Mark onboarding as complete and seed initial content — once.

Called by the mobile app after the user finishes the budget-onboarding
step (bank connected + goals set + budgets set). Triggers first weekly
briefing and challenge generation as background tasks so the home tab
has content immediately.

Idempotent across replicas. The guard is a single atomic UPDATE on
users.onboarding_completed_at (NULL -> now()); only the call whose
UPDATE matches a row spawns the background work. There is no
SELECT-then-UPDATE: with two replicas that is exactly the race that
produced 8 briefing + 8 challenge model calls for one user on 17 Sep.
The stamp is committed before any task is scheduled, so a task can
never start for a call that will later lose the race. Repeat calls
return the same 200 body and spawn nothing.

Both generators run independently — failure of either does NOT block
the onboarding response.

## Response `200`

Successful Response

- unknown

---

[API](https://skmtc.dev/earmarkiq/apis/earmark-api.md) · [All operations](https://skmtc.dev/earmarkiq/apis/earmark-api/llms.txt) · [OpenAPI document](https://skmtc.dev/earmarkiq/apis/earmark-api/revisions/4a2c41907105?raw)
