Skip to main content

REST API Reference

Base URL: https://api.toggletown.com/api/v1

Authentication

The API uses two authentication methods:

MethodHeaderUse case
JWT TokenAuthorization: Bearer <token>Dashboard and management endpoints
SDK API KeyX-API-Key: <api-key>SDK flag fetching

JWT tokens are obtained via the login/signup endpoints and expire after 7 days.

Error Responses

All errors follow a consistent format:

{
"error": {
"message": "Description of what went wrong",
"details": [...] // Optional validation details
}
}
StatusMeaning
400Bad request — validation error
401Unauthorized — missing or invalid auth
403Forbidden — insufficient permissions
404Not found
429Rate limited
500Internal server error

Auth

Sign Up

POST /auth/signup

Body:

FieldTypeRequiredDescription
emailstringYesValid email address
passwordstringYesMin 8 chars, must include uppercase, lowercase, and number

Response 201:

{
"user": {
"id": "uuid",
"email": "user@example.com",
"isAdmin": false,
"plan": "FREE",
"createdAt": "2026-01-01T00:00:00.000Z"
},
"token": "eyJhbG..."
}

Login

POST /auth/login

Body:

FieldTypeRequired
emailstringYes
passwordstringYes

Response 200: Same shape as signup.


Projects

All project endpoints require JWT authentication.

List Projects

GET /projects

Returns all projects where the authenticated user is an owner or member.

Response 200:

{
"projects": [
{
"id": "uuid",
"name": "My App",
"environments": [...],
"_count": { "flags": 5 }
}
]
}

Create Project

POST /projects

Body:

FieldTypeRequiredDescription
namestringYes1–100 characters

Creates the project with default environments (Production, Development). Subject to plan limits.

Response 201:

{
"project": {
"id": "uuid",
"name": "My App",
"environments": [
{ "id": "uuid", "name": "Production", "apiKey": "tt_live_..." },
{ "id": "uuid", "name": "Development", "apiKey": "tt_live_..." }
]
}
}

Get Project

GET /projects/:projectId

Response 200: Project with all environments and flags.

Update Project

PUT /projects/:projectId

Body: { "name": "New Name" }

Requires project owner.

Delete Project

DELETE /projects/:projectId

Requires project owner. Returns 204.


Environments

List Environments

GET /projects/:projectId/environments

Response 200:

{
"environments": [
{ "id": "uuid", "name": "Production", "apiKey": "tt_live_..." }
]
}

Create Environment

POST /projects/:projectId/environments

Body: { "name": "Staging" }

Subject to plan limits.

Rotate API Key

POST /projects/:projectId/environments/:environmentId/rotate-key

Generates a new API key for the environment. The old key is immediately invalidated.

Delete Environment

DELETE /projects/:projectId/environments/:environmentId

Returns 204.


Flags

List Flags

GET /projects/:projectId/flags

Response 200:

{
"flags": [
{
"id": "uuid",
"key": "new-checkout",
"name": "New Checkout",
"type": "BOOLEAN",
"flagEnvironments": [
{
"environmentId": "uuid",
"enabled": true,
"defaultValue": "true",
"rolloutPercentage": 100,
"rules": []
}
]
}
]
}

Create Flag

POST /projects/:projectId/flags

Body:

FieldTypeRequiredDescription
keystringYesKebab-case identifier (e.g., new-checkout)
namestringYesDisplay name, 1–200 characters
descriptionstringNoOptional description
typestringYesBOOLEAN, STRING, NUMBER, or JSON
defaultValueanyNoInitial value
environmentIdstringNoEnvironment to create config in

Get Flag

GET /projects/:projectId/flags/:flagKey

Update Flag

PUT /projects/:projectId/flags/:flagKey

Body: { "name": "Updated Name", "description": "Updated description" }

Delete Flag

DELETE /projects/:projectId/flags/:flagKey

Triggers webhooks. Returns 204.

Toggle Flag

POST /projects/:projectId/flags/:flagKey/toggle/:environmentId

Flips the flag's enabled state for the given environment.

Update Flag Environment Config

PUT /projects/:projectId/flags/:flagKey/environments/:environmentId

Body:

FieldTypeDescription
enabledbooleanEnable/disable the flag
defaultValueanyDefault value when no rules match
rolloutPercentagenumber0–100, percentage of users who get the flag
rulesarrayTargeting rules

Rules format:

{
"rules": [
{
"attribute": "plan",
"operator": "equals",
"value": "pro"
}
]
}

Propagate Flag Config

POST /projects/:projectId/flags/:flagKey/propagate/:sourceEnvId/:targetEnvId

Copies flag configuration from one environment to another.

Evaluate Flag (Preview)

POST /projects/:projectId/flags/:flagKey/evaluate/:environmentId

Body:

{
"userId": "user-123",
"attributes": { "plan": "pro", "country": "US" }
}

Returns the evaluated value and debug information showing the evaluation logic.

Flag History

GET /projects/:projectId/flags/:flagKey/history?limit=50&offset=0

Returns audit log entries for the flag.

Bulk Toggle

POST /projects/:projectId/flags/bulk/toggle

Body:

{
"flagKeys": ["flag-1", "flag-2"],
"environmentId": "uuid",
"enabled": true
}

Bulk Delete

POST /projects/:projectId/flags/bulk/delete

Body: { "flagKeys": ["flag-1", "flag-2"] }


Segments

Segments are reusable groups of targeting rules. Requires Pro plan or above.

List Segments

GET /projects/:projectId/segments

Create Segment

POST /projects/:projectId/segments

Body:

{
"key": "enterprise-users",
"name": "Enterprise Users",
"description": "Users on enterprise plan",
"rules": [
{ "attribute": "plan", "operator": "equals", "value": "enterprise" }
]
}

Get Segment

GET /projects/:projectId/segments/:segmentId

Update Segment

PUT /projects/:projectId/segments/:segmentId

Delete Segment

DELETE /projects/:projectId/segments/:segmentId

Webhooks

Webhooks notify external services when flag changes occur. Requires Pro plan or above.

Events

EventDescription
FLAG_CREATEDA new flag was created
FLAG_UPDATEDFlag metadata was updated
FLAG_DELETEDA flag was deleted
FLAG_TOGGLEDA flag was toggled on/off
FLAG_RULES_UPDATEDTargeting rules were changed
SCHEDULE_EXECUTEDA scheduled change was applied

List Webhooks

GET /projects/:projectId/webhooks

Create Webhook

POST /projects/:projectId/webhooks

Body:

{
"name": "Slack Notifier",
"url": "https://example.com/webhook",
"events": ["FLAG_TOGGLED", "FLAG_CREATED"],
"secret": "optional-signing-secret"
}

URL must use HTTPS. The webhook secret is only returned at creation time.

Update Webhook

PATCH /projects/:projectId/webhooks/:webhookId

Delete Webhook

DELETE /projects/:projectId/webhooks/:webhookId

Test Webhook

POST /projects/:projectId/webhooks/:webhookId/test

Sends a test payload to the webhook URL.

Regenerate Secret

POST /projects/:projectId/webhooks/:webhookId/regenerate-secret

List Deliveries

GET /projects/:projectId/webhooks/:webhookId/deliveries?limit=50

Retry Delivery

POST /projects/:projectId/webhooks/:webhookId/deliveries/:deliveryId/retry

Schedules

Schedule flag changes to apply automatically at a future time.

List Schedules

GET /projects/:projectId/flags/:flagKey/schedules

Create Schedule

POST /projects/:projectId/flags/:flagKey/schedules

Body:

FieldTypeRequiredDescription
environmentIdstringYesTarget environment
changeTypestringYesENABLE, DISABLE, UPDATE_ROLLOUT, or UPDATE_VALUE
newValueanyConditionalRequired for UPDATE_ROLLOUT and UPDATE_VALUE
scheduledAtstringYesISO 8601 datetime (must be in the future)

Update Schedule

PATCH /projects/:projectId/flags/:flagKey/schedules/:scheduleId

Only pending schedules can be updated.

Cancel Schedule

DELETE /projects/:projectId/flags/:flagKey/schedules/:scheduleId

Experiments

Run A/B tests linked to feature flags.

Create Experiment

POST /projects/:projectId/experiments

Body:

{
"flagId": "uuid",
"environmentId": "uuid",
"name": "Checkout Flow Test",
"hypothesis": "New checkout will increase conversions",
"variants": [
{ "name": "control", "value": "old", "trafficAllocation": 50 },
{ "name": "treatment", "value": "new", "trafficAllocation": 50 }
],
"primaryMetric": "checkout_completed"
}

Traffic allocation must sum to 100%.

List Experiments

GET /projects/:projectId/experiments?status=RUNNING

Get Experiment

GET /projects/:projectId/experiments/:id

Update Experiment

PATCH /projects/:projectId/experiments/:id

Only experiments in DRAFT status can be updated.

Start / Pause / Resume / Complete

POST /projects/:projectId/experiments/:id/start
POST /projects/:projectId/experiments/:id/pause
POST /projects/:projectId/experiments/:id/resume
POST /projects/:projectId/experiments/:id/complete

Complete accepts optional body: { "winnerVariant": "treatment", "applyWinner": true }

Get Results

GET /projects/:projectId/experiments/:id/results?days=30

Track Event (SDK)

POST /sdk/experiments/track

Auth: SDK API Key (X-API-Key header)

Body:

{
"userId": "user-123",
"eventName": "checkout_completed",
"flagKey": "checkout-flow"
}

SDK

Get Flags

GET /sdk/flags

Auth: SDK API Key (X-API-Key header)

This is the endpoint all SDKs poll. Returns all flag configurations for the environment associated with the API key.

Response 200:

{
"flags": {
"new-checkout": {
"enabled": true,
"type": "BOOLEAN",
"defaultValue": "true",
"rolloutPercentage": 50,
"rules": [
{
"attribute": "plan",
"operator": "equals",
"value": "pro"
}
]
}
},
"timestamp": "2026-01-01T00:00:00.000Z"
}

Includes cache headers (X-Cache: HIT or X-Cache: MISS) when Redis caching is enabled.


Audit Logs

GET /projects/:projectId/audit-logs?limit=50&offset=0&environmentId=uuid

Returns flag change history for the project. Retention depends on plan:

PlanRetention
Free7 days
Pro90 days
TeamUnlimited
EnterpriseUnlimited

Statistics

GET /projects/:projectId/statistics?days=7

Returns evaluation statistics for the project over the given time period (1–30 days).


Usage & Billing

Get Usage

GET /usage

Returns current usage against plan limits.

Usage History

GET /usage/history

Returns monthly usage snapshots for the last 12 months.

Create Checkout

POST /billing/checkout

Body: { "plan": "PRO" }

Returns a checkout URL for Lemon Squeezy.

Customer Portal

POST /billing/portal

Returns a URL to the billing management portal.


Rate Limits

The API enforces rate limits to ensure fair usage. When rate limited, you'll receive a 429 response with a Retry-After header.