Onboarding wizard lifecycle
The Home dashboard shows a getting-started checklist of nine canonical steps — verify your email, create and name the workspace, add a payment method, receive the trial credit, buy a number, send a first message, add a first contact, and pick up one advanced item (a campaign, an agent, or a teammate invite). The server computes every step from live platform data on each read; no state lives in the browser. This page defines the step states, the probe semantics, the manual overrides, and the one compliance gate that hides a step. The checklist answers “what should I do next to become productive.” A separate surface — Onboarding status timeline under Settings → Onboarding Status — answers “where is my go-live verification stuck” across KYC, 10DLC, country profiles, and per-number registration. Section 7 maps the difference.1. The wizard state machine
Steps are served in six endpoints. Two carry the actual wizard UI; four reinforce it.GET /api/v1/onboarding/status— the main checklist. Returns the nine steps, each withcompleted,completedAt,completedBy("system"or"user"), plus totals (completedCount,totalCount,overallPct) and anextIncompleteStepsummary used by the resume banner shown on other dashboard pages.POST /api/v1/onboarding/complete-stepandPOST /api/v1/onboarding/skip-step— write a manual override for one step; see Section 4. Either changes the response shape on the nextGET /statuspoll.GET /api/v1/onboarding/sms-checklist— a five-probe fast read for the SMS getting-started panel (API key, number, sender Id, first SMS send, webhook).GET /api/v1/onboarding/provisioning-status— the signup gate (email verified, tenant schema ready, first API key seeded, plus a volatile trial-credit signal). The provisioning panel polls this every ~2 seconds during the post-signup window.GET /api/v1/onboarding/status-timeline— the verification-timeline spillover covered in Section 7.
GET /status is in exactly one of three states — pending (no signal), complete, or complete-by-override. There is no in-progress state; a step either has a satisfying probe row or it does not. complete and complete-by-override differ only by the completedBy marker ("system" vs "user").
The nine canonical steps
All steps are read in one shape: a label, a description, actaUrl (the dashboard route the step links to), and a stable id. The ids are the same ids the complete-step and skip-step endpoints accept; the validator rejects any other id with a 422.
Readable labels resolve into the nine ids the complete/skip endpoints take; the ids are stable API contract values and safe to hard-code in integrations.
2. The probe model
GET /status derives every step from underlying rows rather than state persisted on the requester’s progress. At most ~9 cheap SELECT ... LIMIT 1 probes run per cache miss, all behind a 60-second Redis cache scoped per (workspace, user), so the dashboard polls on every Home render without paying the derivation.
Two examples of probe semantics that are not “row exists”:
- Workspace identity. A workspace row is provisioned automatically at signup, so the naive probe (
organization.name is not null) would satisfy steps 2 and 3 the instant you reach the dashboard. Instead, both steps wait until the operator has set a real, chosen name, using the explicit placeholder flag stamped at provisioning when present and a name-pattern fallback for older workspaces. - Trial credit ledger. Step 5 looks for the trial-grant ledger entry keyed to the workspace, written when the grant executes. Absence of the row is “not yet granted” — it never blocks the dashboard past the cache cycle that follows the grant.
GET /status read never hangs, and a degraded read is indistinguishable from a genuinely-incomplete state for one cache cycle.
3. Partial success — one passing probe satisfies a step
Step 9 is the one step satisfied by any of three channels: a campaign exists, an agent exists, or a second user accepted an invite. The derivation returns whichever of the three probes completes earliest, and the step flips as soon as one of them passes. The checklist stays honest about the funnel: reaching “platform graduate” needs exactly one of the three — you do not need all of them. Partial-success semantics extend across the read path. Each probe fails closed on itself — a probe that cannot reach its data resolves topending for its step rather than failing the whole checklist, and the other steps still resolve independently. Operators see a settled checklist even while part of the backend is degraded.
4. Operator overrides — complete or skip a step
Two write endpoints store a per-(workspace, user, step) override:POST /api/v1/onboarding/complete-step— the operator marks a step done (“Mark as done” in the dashboard).POST /api/v1/onboarding/skip-step— the operator dismisses a step that does not apply (e.g. payment method on a sandbox-only workspace).
{ "stepId": one-of-the-nine }; anything else is a 422. Both endpoints require admin-or-higher privileges and write an audit-log entry, so a teammate with a viewer or billing role cannot move your checklist.
An override applies to the operator’s own checklist view — the key is the pair (workspace, user) — while probe-derived steps complete for the workspace irrespective of who polls. This is deliberate: the derivation reflects reality; your override reflects your declared intent. A probe-driven completion stays completedBy: "system"; an override flips the marker to completedBy: "user" without rewriting completedAt.
Overrides persist idempotently — re-marking a step re-upserts the row, and the intent (manual_complete or skipped) is recorded even though the checklist treats both as “complete.” The distinction is retained for analytics over which steps operators skip.
5. KYC gates the trial-credit step’s visibility
Step 5 (trial credit) has a compliance visibility rule the other eight steps do not share:- KYC not approved. The step is hidden from the checklist entirely — excluded from
steps[]and from the totals — unless the grant already landed (either a real completion signal or an operator override). The step’s description never says “submit KYC now” once you have; it adapts topending_review(“KYC submitted — under review (usually < 24h).”),rejected(“contact support to resolve”), andapproved(grant is in-flight). The KYC banner on the dashboard covers the review state with its own copy and link, so the checklist does not repeat it. - KYC approved. The step reappears on the next
GET /statuspoll (within one cache cycle).
Settings → KYC page; the checklist only surfaces or hides the step.
6. SMS checklist and provisioning-status are sibling surfaces
- SMS checklist (
GET /sms-checklist) runs five per-surface probes (active API key, number, approved SMS sender, an SMS that reachedsent/delivered, active webhook) behind a 30-second cache. It powers the SMS getting-started panel instead of hitting six endpoints. - Provisioning status (
GET /provisioning-status) exposes three blocks — email verified, tenant schema ready, at least one API key seeded — plus a volatile trial-credit signal. The signup provisioning panel polls it every ~2 seconds with a 5-second cache so the rows advance in near real time. Trial credit is informational there: the three blocking signals are email, schema, and API key.
7. Wizard vs verification timeline
The wizard and the timeline are deliberately two surfaces:- This page (the wizard). “What should I do to become productive” — nine steps derived from platform-usage data, with operator overrides. Lives at Home, reachable for most users through the resume banner.
- Onboarding status timeline. “Where is my go-live verification stuck” — a read aggregation across account KYC, 10DLC brands and campaigns, per-country compliance profiles, and per-number registration. Lives at Settings → Onboarding Status, the surface where reviewers, blocks, SLA, and resolution links are tracked.