Waitlist
During Chronary’s private preview the open signup endpoints are gated. Instead, callers — both humans (via the console form at console.chronary.ai/waitlist) and bots (via this API) — POST to /v1/waitlist to enroll. A real organization row is created in the database, flagged with is_waitlisted: true. No API keys are issued and data-plane endpoints return 403 until an admin flips the flag.
This endpoint is idempotent: a second join with the same email returns the existing waitlisted org. An active (non-waitlisted) account at the same email returns 409 email_taken — direct the user to sign in instead.
Join the waitlist
Section titled “Join the waitlist”POST /v1/waitlistUnauthenticated. IP-rate-limited and per-email-rate-limited via the public auth limiter.
Request body
Section titled “Request body”| Field | Type | Required | Description |
|-------|------|----------|-------------|
| email | string | yes | Email address to enroll |
| name | string | no | Display name (2–100 chars). Defaults to the email’s local-part. |
| tos_version | string | no | Exact ToS version string the caller has accepted. Recommended for compliance — the value is recorded in tos_acceptances with source = 'waitlist_join'. |
Example
Section titled “Example”curl -X POST https://api.chronary.ai/v1/waitlist \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "tos_version": "2026-04-17" }'import { Chronary } from '@chronary/sdk';
// Construct without an API key — the waitlist endpoint is unauthenticated.const client = new Chronary();
const result = await client.waitlist.join({ tos_version: '2026-04-17',});
console.log(result.data.id); // org UUIDconsole.log(result.data.is_waitlisted); // trueconsole.log(result.message); // "You're on the list..."from chronary import Chronary
client = Chronary(api_key=None)
result = client.waitlist.join( tos_version="2026-04-17",)
print(result.data.id) # org UUIDprint(result.data.is_waitlisted) # Trueprint(result.message) # "You're on the list..."chronary auth waitlist \ --tos-version 2026-04-17Response
Section titled “Response”201 Created (fresh join) or 200 OK (idempotent re-hit):
{ "data": { "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "name": "dev", "is_waitlisted": true, "waitlisted_at": "2026-05-05T12:00:00.000Z", "signup_source": "console" }, "message": "You're on the list. Check your email for a confirmation."}A confirmation email is sent on the fresh-join branch. The idempotent branch skips the email so retries don’t spam.
Errors
Section titled “Errors”| Status | Type | When |
|---|---|---|
| 400 | validation_error | Email is missing or not a valid email address |
| 409 | email_taken | An active (non-waitlisted) account already exists for this email |
| 409 | tos_version_stale | Submitted tos_version doesn’t match the current manifest. Includes current_version to retry with. |
| 429 | rate_limit_error | Per-IP or per-email waitlist limit exceeded. Honor Retry-After. |
What waitlisted accounts can do
Section titled “What waitlisted accounts can do”A waitlisted org row is real but heavily gated:
- Cannot create API keys.
POST /v1/auth/keys/regenerateand/v1/auth/keys/scopedreturn403 account_waitlisted. - Cannot hit data-plane endpoints. Any
/v1/*request (other than/v1/auth/*,/v1/waitlist,/v1/plans,/v1/internal,/v1/admin) returns403 account_waitlistedif it ever reaches an authenticated path with a key whose org is waitlisted. - Can sign in. OAuth and email-verified login still work — the console redirects waitlisted sessions to
/waitlist/pending. - Receives an activation email when an admin flips
is_waitlistedtofalseviaPOST /v1/admin/orgs/:id/activate.