/v1/workspaces/{workspace_id}/rally/settingsAuthRead workspace-level Rally defaults
Path parameters
workspace_id*stringResponse · 200
Workspace Rally settings.
Public signup endpoints anyone can hit from a frontend, plus the admin endpoints that drive the console. Every endpoint generated from the live OpenAPI spec.
Rally exposes two surfaces. The public surface at /v1/waitlists/{workspaceSlug}/{waitlistSlug} takes anonymous signups — drop the URL into your marketing site or share it directly. The admin surface under /v1/workspaces/{workspaceId}/... is what the console uses to create waitlists, manage entries, and configure webhooks. Both are documented below.
Base URL
https://api.rally.productcraft.coAuth
Authorization: Bearer …Spec version
OpenAPI spec
https://api.rally.productcraft.co/docs-json/v1/workspaces/{workspace_id}/rally/settingsAuthPath parameters
workspace_id*stringResponse · 200
Workspace Rally settings.
/v1/workspaces/{workspace_id}/rally/settingsAuthPath parameters
workspace_id*stringRequest body
default_sender_domain_idstringEnvoi (mailbox-api) domain UUID to use as default sender for Rally notifications. null clears the override.
default_heimdall_app_slugstringHeimdall consumer-app slug to invite approved entries into. null clears the link.
brand_namestringBrand name returned in the public waitlist payload. Customer frontends render it on their own signup form.
brand_logo_urlstringLogo URL returned in the public waitlist payload. Customer frontends render it on their own signup form.
primary_colorstringPrimary brand colour as #RRGGBB
notifications_via_envoibooleanRoute Rally notifications via Envoi (workspace sender domain + per-event template selection) instead of staying silent. Requires default_sender_domain_id, default_sender_address, and a template name for every supported event. Default false; when off, Rally sends no notification emails and the customer is expected to handle email via the webhook lane.
default_sender_addressstringVerified sender address used as the From envelope on Rally notifications. Must belong to default_sender_domain_id. null clears the override.
welcome_template_namestringEnvoi template name used for entry.created notifications. Must already exist in the workspace template store.
approved_template_namestringEnvoi template name used for entry.approved notifications. Must already exist in the workspace template store.
rejected_template_namestringEnvoi template name used for entry.rejected notifications. Must already exist in the workspace template store.
Response · 200
Updated workspace Rally settings.
Example
Request
PUT /v1/workspaces/{workspace_id}/rally/settings
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"default_sender_domain_id": "string",
"default_heimdall_app_slug": "string",
"brand_name": "string",
"brand_logo_url": "string",
"primary_color": "string",
"notifications_via_envoi": false,
"default_sender_address": "string",
"welcome_template_name": "string",
"approved_template_name": "string",
"rejected_template_name": "string"
}/v1/workspaces/{workspace_id}/waitlistsAuthPath parameters
workspace_id*stringQuery parameters
limitnumbercursorstringOpaque cursor for pagination
statusstringFilter by status
Response · 200 Page of waitlists.
data*arraypagination*objectnext_cursor*stringhas_more*booleanExample
Request
GET /v1/workspaces/{workspace_id}/waitlists
Authorization: Bearer YOUR_TOKENResponse
{
"data": [
{
"id": "b1a4...",
"workspace_id": "b1a4...",
"workspace_slug": "acme",
"slug": "early-access",
"display_name": "Early Access Program",
"description": "string",
"status": "draft",
"settings": {},
"created_by": "string",
"previous_workspace_slug": "string",
"created_at": "string",
"updated_at": "string"
}
],
"pagination": {
"next_cursor": "string",
"has_more": false
}
}/v1/workspaces/{workspace_id}/waitlistsAuthPath parameters
workspace_id*stringHeaders
Idempotency-KeystringStripe-style idempotency key. Waitlist creation provisions a non-trivial sub-tree (variant, default referral settings, etc.); a retry without this header creates a second waitlist sharing the same name slug. 24h TTL.
Request body
slug*stringURL-safe slug
Example: "early-access"
display_name*stringDisplay name
Example: "Early Access Program"
descriptionstringDescription returned in the public waitlist payload — customer frontends typically render it under the display name on their signup form.
settingsobjectWaitlist settings (max_entries, approval_required, custom_fields, confirmation_message, referral_boost)
Response · 201 Waitlist created.
id*stringExample: "b1a4..."
workspace_id*stringExample: "b1a4..."
workspace_slug*stringExample: "acme"
slug*stringExample: "early-access"
display_name*stringExample: "Early Access Program"
description*stringstatus*enum (4)settings*objectWaitlist settings (max_entries, approval_required, custom_fields, confirmation_message, referral_boost).
created_by*stringprevious_workspace_slug*stringcreated_at*stringupdated_at*stringExample
Request
POST /v1/workspaces/{workspace_id}/waitlists
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"slug": "early-access",
"display_name": "Early Access Program",
"description": "string",
"settings": {}
}Response
{
"id": "b1a4...",
"workspace_id": "b1a4...",
"workspace_slug": "acme",
"slug": "early-access",
"display_name": "Early Access Program",
"description": "string",
"status": "draft",
"settings": {},
"created_by": "string",
"previous_workspace_slug": "string",
"created_at": "string",
"updated_at": "string"
}/v1/workspaces/{workspace_id}/waitlists/{id}AuthPath parameters
id*stringResponse · 200 Waitlist row.
id*stringExample: "b1a4..."
workspace_id*stringExample: "b1a4..."
workspace_slug*stringExample: "acme"
slug*stringExample: "early-access"
display_name*stringExample: "Early Access Program"
description*stringstatus*enum (4)settings*objectWaitlist settings (max_entries, approval_required, custom_fields, confirmation_message, referral_boost).
created_by*stringprevious_workspace_slug*stringcreated_at*stringupdated_at*stringExample
Request
GET /v1/workspaces/{workspace_id}/waitlists/{id}
Authorization: Bearer YOUR_TOKENResponse
{
"id": "b1a4...",
"workspace_id": "b1a4...",
"workspace_slug": "acme",
"slug": "early-access",
"display_name": "Early Access Program",
"description": "string",
"status": "draft",
"settings": {},
"created_by": "string",
"previous_workspace_slug": "string",
"created_at": "string",
"updated_at": "string"
}/v1/workspaces/{workspace_id}/waitlists/{id}AuthPath parameters
id*stringRequest body
display_namestringNew display name
descriptionstringNew description
settingsobjectUpdated settings (merged shallow)
Response · 200 Waitlist updated.
id*stringExample: "b1a4..."
workspace_id*stringExample: "b1a4..."
workspace_slug*stringExample: "acme"
slug*stringExample: "early-access"
display_name*stringExample: "Early Access Program"
description*stringstatus*enum (4)settings*objectWaitlist settings (max_entries, approval_required, custom_fields, confirmation_message, referral_boost).
created_by*stringprevious_workspace_slug*stringcreated_at*stringupdated_at*stringExample
Request
PATCH /v1/workspaces/{workspace_id}/waitlists/{id}
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"display_name": "string",
"description": "string",
"settings": {}
}Response
{
"id": "b1a4...",
"workspace_id": "b1a4...",
"workspace_slug": "acme",
"slug": "early-access",
"display_name": "Early Access Program",
"description": "string",
"status": "draft",
"settings": {},
"created_by": "string",
"previous_workspace_slug": "string",
"created_at": "string",
"updated_at": "string"
}/v1/workspaces/{workspace_id}/waitlists/{id}AuthPath parameters
id*stringResponse · 204
Waitlist deleted.
/v1/workspaces/{workspace_id}/waitlists/{id}/statusAuthPath parameters
id*stringRequest body
status*enum (4)New status
Response · 200 Status updated.
id*stringExample: "b1a4..."
workspace_id*stringExample: "b1a4..."
workspace_slug*stringExample: "acme"
slug*stringExample: "early-access"
display_name*stringExample: "Early Access Program"
description*stringstatus*enum (4)settings*objectWaitlist settings (max_entries, approval_required, custom_fields, confirmation_message, referral_boost).
created_by*stringprevious_workspace_slug*stringcreated_at*stringupdated_at*stringExample
Request
PATCH /v1/workspaces/{workspace_id}/waitlists/{id}/status
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"status": "draft"
}Response
{
"id": "b1a4...",
"workspace_id": "b1a4...",
"workspace_slug": "acme",
"slug": "early-access",
"display_name": "Early Access Program",
"description": "string",
"status": "draft",
"settings": {},
"created_by": "string",
"previous_workspace_slug": "string",
"created_at": "string",
"updated_at": "string"
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entriesAuthPath parameters
workspace_id*stringwaitlist_id*stringQuery parameters
limitnumbercursorstringOpaque cursor for pagination
statusstringFilter by status
Response · 200 Page of entries with pagination cursor.
data*arraypagination*objectnext_cursor*stringhas_more*booleanExample
Request
GET /v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries
Authorization: Bearer YOUR_TOKENResponse
{
"data": [
{
"id": "string",
"waitlist_id": "string",
"workspace_id": "string",
"email": "string",
"name": "string",
"interest": "string",
"referrer": "string",
"referral_code": "string",
"referral_count": 0,
"referred_by_entry_id": "string",
"position": 0,
"status": "pending",
"invited_at": "string",
"invited_to_app_slug": "string",
"metadata": {},
"created_at": "string",
"updated_at": "string"
}
],
"pagination": {
"next_cursor": "string",
"has_more": false
}
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/countAuthPath parameters
workspace_id*stringwaitlist_id*stringResponse · 200
No content.
/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/export.csvAuthPath parameters
workspace_id*stringwaitlist_id*stringResponse · 200
CSV stream
/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/{entry_id}AuthPath parameters
workspace_id*stringwaitlist_id*stringentry_id*stringResponse · 200 Entry row.
id*stringwaitlist_id*stringworkspace_id*stringemail*stringname*stringinterest*stringreferrer*stringreferral_code*stringreferral_count*numberreferred_by_entry_id*stringposition*numberstatus*enum (3)invited_at*stringinvited_to_app_slug*stringmetadata*objectcreated_at*stringupdated_at*stringExample
Request
GET /v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/{entry_id}
Authorization: Bearer YOUR_TOKENResponse
{
"id": "string",
"waitlist_id": "string",
"workspace_id": "string",
"email": "string",
"name": "string",
"interest": "string",
"referrer": "string",
"referral_code": "string",
"referral_count": 0,
"referred_by_entry_id": "string",
"position": 0,
"status": "pending",
"invited_at": "string",
"invited_to_app_slug": "string",
"metadata": {},
"created_at": "string",
"updated_at": "string"
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/{entry_id}AuthPath parameters
workspace_id*stringwaitlist_id*stringentry_id*stringRequest body
status*enum (2)Target status
Response · 200 Entry status updated.
id*stringwaitlist_id*stringworkspace_id*stringemail*stringname*stringinterest*stringreferrer*stringreferral_code*stringreferral_count*numberreferred_by_entry_id*stringposition*numberstatus*enum (3)invited_at*stringinvited_to_app_slug*stringmetadata*objectcreated_at*stringupdated_at*stringExample
Request
PATCH /v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/{entry_id}
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"status": "approved"
}Response
{
"id": "string",
"waitlist_id": "string",
"workspace_id": "string",
"email": "string",
"name": "string",
"interest": "string",
"referrer": "string",
"referral_code": "string",
"referral_count": 0,
"referred_by_entry_id": "string",
"position": 0,
"status": "pending",
"invited_at": "string",
"invited_to_app_slug": "string",
"metadata": {},
"created_at": "string",
"updated_at": "string"
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/{entry_id}AuthPath parameters
workspace_id*stringwaitlist_id*stringentry_id*stringResponse · 204
Entry deleted.
/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/{entry_id}/invite-to-appAuthPath parameters
workspace_id*stringwaitlist_id*stringentry_id*stringRequest body
app_slugstringHeimdall app slug to invite into; defaults to rally_settings.default_heimdall_app_slug
send_emailbooleanSend the rally/approved email with the Heimdall invite link baked in
Response · 200
Invite created in Heimdall
Example
Request
POST /v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/{entry_id}/invite-to-app
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"app_slug": "string",
"send_email": false
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/bulkAuthPath parameters
workspace_id*stringwaitlist_id*stringRequest body
ids*arrayEntry UUIDs to act on in this batch. Capped at 100 per call; the request is processed serially and per-row results are returned. De-duped server-side.
Example: ["11111111-1111-1111-1111-111111111111","22222222-2222-2222-2222-222222222222"]
action*enum (3)Action to apply to every id.
Example: "approve"
app_slugstringHeimdall app slug override for `action: invite-to-app`. When omitted, falls back to `rally_settings.default_heimdall_app_slug`. Ignored for approve/reject.
Example: "acme-product"
send_emailbooleanWhether to send the rally/approved email with the invite link baked in. Defaults to `true`. Ignored for approve/reject.
Response · 200
`{ requested, succeeded, failed, results }`. Each row in `results` carries `{ id, status: "ok" | "error", error?: { code, message } }` so a partial failure (one bad id) doesn't fail the whole batch.
Example
Request
POST /v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/entries/bulk
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"ids": [
"11111111-1111-1111-1111-111111111111",
"22222222-2222-2222-2222-222222222222"
],
"action": "approve",
"app_slug": "acme-product",
"send_email": false
}/v1/waitlists/{workspace_slug}/{waitlist_slug}Path parameters
workspace_slug*stringwaitlist_slug*stringQuery parameters
langstringBCP-47 locale tag (e.g. `en`, `pt-BR`). Wins over Accept-Language when picking the variant.
Response · 200
Public waitlist info
/v1/waitlists/{workspace_slug}/{waitlist_slug}/leaderboardPath parameters
workspace_slug*stringwaitlist_slug*stringQuery parameters
limitstringNumber of rows (1-50, default 50)
Response · 200
Array of `{ position, referral_count, masked_email }`
/v1/waitlists/{workspace_slug}/{waitlist_slug}/entriesPath parameters
workspace_slug*stringwaitlist_slug*stringRequest body
email*stringEmail address
Example: "ada@example.com"
name*stringFull name
Example: "Ada Lovelace"
intereststringFree-text product interest
referrerstringHow they heard about it
referral_codestringReferral code from a prior signup; bumps that signup’s position when honoured
metadataobjectCustom field values
recaptcha_tokenstringreCAPTCHA v3 token; verified server-side when the waitlist has settings.recaptcha_site_key
variant_idstring · uuidVariant id this submission was attributed to. Customer frontends fetch the active variant from `GET /v1/waitlists/:workspaceSlug/:waitlistSlug` and round-trip it here on POST so per-variant conversion can be computed without a separate impressions table.
Response · 201
Entry created
Example
Request
POST /v1/waitlists/{workspace_slug}/{waitlist_slug}/entries
Content-Type: application/json
{
"email": "ada@example.com",
"name": "Ada Lovelace",
"interest": "string",
"referrer": "string",
"referral_code": "string",
"metadata": {},
"recaptcha_token": "string",
"variant_id": "00000000-0000-0000-0000-000000000000"
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/analyticsAuthPath parameters
workspace_id*stringwaitlist_id*stringResponse · 200
Aggregated analytics payload for the waitlist.
/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/analytics/timelineAuthPath parameters
workspace_id*stringwaitlist_id*stringQuery parameters
since*stringISO-8601 inclusive start
until*stringISO-8601 exclusive end
Response · 200
Daily timeline array, oldest first, zero-count days included.
/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/variantsAuthPath parameters
workspace_id*stringwaitlist_id*stringResponse · 200 Bare array of variants
data*arrayExample
Request
GET /v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/variants
Authorization: Bearer YOUR_TOKENResponse
{
"data": [
{
"id": "string",
"waitlist_id": "string",
"kind": "ab",
"locale": "string",
"copy": {},
"weight": 0,
"active": false,
"created_at": "string"
}
]
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/variantsAuthPath parameters
workspace_id*stringwaitlist_id*stringRequest body
kind*enum (2)locale*stringBCP-47 locale tag. For ab variants this is the locale they target; for locale variants this is the locale they serve. Case is normalised on the public side.
Example: "en"
copy*objectCopy overrides. Recognised keys: display_name, description, confirmation_message. Unknown keys are dropped on the public render.
weightnumberRelative weight inside the ab pool. Ignored when kind=locale. Default 1.
activebooleanResponse · 201 Variant created
id*stringwaitlist_id*stringkind*enum (2)locale*stringcopy*objectweight*numberactive*booleancreated_at*stringExample
Request
POST /v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/variants
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"kind": "ab",
"locale": "en",
"copy": {},
"weight": 0,
"active": false
}Response
{
"id": "string",
"waitlist_id": "string",
"kind": "ab",
"locale": "string",
"copy": {},
"weight": 0,
"active": false,
"created_at": "string"
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/variants/{id}AuthPath parameters
workspace_id*stringwaitlist_id*stringid*stringRequest body
localestringcopyobjectdisplay_namestringdescriptionstringconfirmation_messagestringweightnumberactivebooleanResponse · 200 Variant updated
id*stringwaitlist_id*stringkind*enum (2)locale*stringcopy*objectweight*numberactive*booleancreated_at*stringExample
Request
PATCH /v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/variants/{id}
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"locale": "string",
"copy": {
"display_name": "string",
"description": "string",
"confirmation_message": "string"
},
"weight": 0,
"active": false
}Response
{
"id": "string",
"waitlist_id": "string",
"kind": "ab",
"locale": "string",
"copy": {},
"weight": 0,
"active": false,
"created_at": "string"
}/v1/workspaces/{workspace_id}/waitlists/{waitlist_id}/variants/{id}AuthPath parameters
workspace_id*stringwaitlist_id*stringid*stringResponse · 204
Variant deleted
/v1/workspaces/{workspace_id}/webhooksAuthPath parameters
workspace_id*stringResponse · 200 Webhooks for the workspace.
data*arrayExample
Request
GET /v1/workspaces/{workspace_id}/webhooks
Authorization: Bearer YOUR_TOKENResponse
{
"data": [
{
"id": "string",
"workspace_id": "string",
"url": "string",
"events": [
"entry.created"
],
"active": false,
"failure_count": 0,
"last_status_code": 0,
"last_attempt_at": "string",
"auto_disabled_at": "string",
"first_failure_at": "string",
"created_at": "string"
}
]
}/v1/workspaces/{workspace_id}/webhooksAuthPath parameters
workspace_id*stringHeaders
Idempotency-KeystringStripe-style idempotency key. The signing secret is returned exactly once; a retry without this header creates a second webhook + secret you never see the plaintext for. 24h TTL.
Request body
url*stringDestination URL (must be https in prod)
events*arrayEvents to subscribe to
Example: ["entry.created","entry.approved"]
activebooleanDisabled webhooks store events but never deliver
Response · 201 Webhook created. Includes plaintext `signing_secret` exactly once.
id*stringworkspace_id*stringurl*stringevents*arrayactive*booleanfailure_count*numberlast_status_code*numberlast_attempt_at*stringauto_disabled_at*stringfirst_failure_at*stringcreated_at*stringsigning_secret*stringPlaintext signing secret returned EXACTLY ONCE on create + rotate. Persist immediately — it does not appear on subsequent GETs.
Example
Request
POST /v1/workspaces/{workspace_id}/webhooks
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"url": "string",
"events": [
"entry.created",
"entry.approved"
],
"active": false
}Response
{
"id": "string",
"workspace_id": "string",
"url": "string",
"events": [
"entry.created"
],
"active": false,
"failure_count": 0,
"last_status_code": 0,
"last_attempt_at": "string",
"auto_disabled_at": "string",
"first_failure_at": "string",
"created_at": "string",
"signing_secret": "string"
}/v1/workspaces/{workspace_id}/webhooks/{id}AuthPath parameters
workspace_id*stringid*stringResponse · 200 Webhook row.
id*stringworkspace_id*stringurl*stringevents*arrayactive*booleanfailure_count*numberlast_status_code*numberlast_attempt_at*stringauto_disabled_at*stringfirst_failure_at*stringcreated_at*stringExample
Request
GET /v1/workspaces/{workspace_id}/webhooks/{id}
Authorization: Bearer YOUR_TOKENResponse
{
"id": "string",
"workspace_id": "string",
"url": "string",
"events": [
"entry.created"
],
"active": false,
"failure_count": 0,
"last_status_code": 0,
"last_attempt_at": "string",
"auto_disabled_at": "string",
"first_failure_at": "string",
"created_at": "string"
}/v1/workspaces/{workspace_id}/webhooks/{id}AuthPath parameters
workspace_id*stringid*stringRequest body
urlstringNew URL
eventsarrayNew event subscription
activebooleanPause/resume the webhook
Response · 200
No content.
Example
Request
PATCH /v1/workspaces/{workspace_id}/webhooks/{id}
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"url": "string",
"events": [
"entry.created"
],
"active": false
}/v1/workspaces/{workspace_id}/webhooks/{id}AuthPath parameters
workspace_id*stringid*stringResponse · 204
No content.
/v1/workspaces/{workspace_id}/webhooks/{id}/deliveriesAuthPath parameters
workspace_id*stringid*stringResponse · 200
`{ data: Array<{ id, event_id, event_type, attempt_number, status_code, response_body, error_message, latency_ms, created_at }> }`
/v1/workspaces/{workspace_id}/webhooks/{id}/rotate-secretAuthPath parameters
workspace_id*stringid*stringResponse · 201
No content.
/v1/workspaces/{workspace_id}/webhooks/{id}/testAuthPath parameters
workspace_id*stringid*stringRequest body
event*enum (3)Event type to fire as a synthetic test
waitlist_idstringWaitlist UUID to reference in the synthetic payload. Defaults to a placeholder UUID when omitted.
Response · 202
No content.
Example
Request
POST /v1/workspaces/{workspace_id}/webhooks/{id}/test
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{
"event": "entry.created",
"waitlist_id": "string"
}