Self Serve Signup API
Source: docs/runbooks/self-serve-signup-api.md
---
title: Self-Serve Signup API Runbook
description: Operational runbook for signup session lifecycle, verification, provisioning retries, and incident troubleshooting.
owner: ops
last_reviewed: 2026-03-03
audience: internal
status: active
---
# Self-Serve Signup API Runbook
Purpose: operate and troubleshoot the public signup API flow used by customers and agent-driven onboarding.
## Prerequisites
Required environment variables:
- `SELF_SERVE_SIGNUP_ENABLED`
- `RESEND_API_KEY`
- `RESEND_FROM_EMAIL`
- `SIGNUP_OTP_TEMPLATE_ID`
- `SIGNUP_PROVISIONED_TEMPLATE_ID`
- `OTP_PEPPER`
- `KEY_HASH_SECRET`
- `CLERK_SECRET_KEY`
## API flow
1. Create session
- `POST /api/public/signup/sessions`
- Input includes company info, slug, modules, admin email, legal acceptance snapshot.
- Output: `sessionId`, OTP verification window, session expiry.
2. Verify email
- `POST /api/public/signup/sessions/:sessionId/verify-email`
- Input: 6-digit OTP.
- Output: session status (`EMAIL_VERIFIED`).
3. Provision (resumable)
- `POST /api/public/signup/sessions/:sessionId/provision`
- Input: `idempotencyKey` and optional integration-key template.
- Output:
- `201` + `PROVISIONED` when complete,
- `202` + `REVIEW_REQUIRED` when manual intervention is needed.
4. Poll status
- `GET /api/public/signup/sessions/:sessionId`
- Use for agents to resume provisioning decisions.
## Provisioning step contract
Step markers persisted in `provisionStepState`:
- `tenant_created_at`
- `clerk_org_created_at`
- `clerk_invite_sent_at`
- `detectors_seeded_at`
- `integration_key_created_at`
- `legal_acceptance_recorded_at`
- `bootstrap_token_issued_at`
Retries resume at the first incomplete step.
## Feature-off behavior
When `SELF_SERVE_SIGNUP_ENABLED=false`:
- all `/api/public/signup/*` endpoints return:
- `503`
- `code: FEATURE_DISABLED`
- `details.retryAfterSeconds`
## Common failures
- `RATE_LIMITED`: create/verify threshold exceeded (IP, domain, or email scope).
- `INVALID_REQUEST`: malformed slug, module set, OTP, or idempotency payload.
- `REVIEW_REQUIRED`: dependency or provider issue (for example Clerk/Resend/secret configuration).
## Recovery checklist
1. Check session status via `GET /api/public/signup/sessions/:sessionId`.
2. Confirm required env vars are present and valid.
3. Re-run `POST .../provision` with new idempotency key.
4. If still `REVIEW_REQUIRED`, escalate with `sessionId` and `failureReason`.