API Reference
Overview
The IntelliToggle API is a REST API that enables you to manage feature flags, projects, tenants, and user access programmatically. This reference covers all available endpoints, request/response formats, and authentication methods.
The canonical documented API surface is versioned under /api/v1/….
Legacy aliases such as /api/…, /auth/…, /oauth/…, and older
admin-domain paths may remain implemented temporarily during migration, but new
integrations should use the versioned routes documented here.
Authentication
Bearer Authentication
Most endpoints require authentication using Firebase ID token bearer auth.
Authorization: Bearer <your-jwt-token>
OAuth 2.0
For machine-to-machine authentication, use OAuth 2.0 client credentials flow. This is the correct authentication model for third-party backend services. User Firebase tokens are for dashboard and user-session calls, not production service-to-service integrations.
The client credentials flow does not use redirect URLs. Create credentials in the same IntelliToggle environment you call at runtime; development credentials should be sent to the development API, and production credentials should be sent to https://api.intellitoggle.com.
POST /api/v1/oauth/token
Exchange client credentials for an access token.
Request Body (application/x-www-form-urlencoded):
grant_type=client_credentials
client_id=<your-client-id>
client_secret=<your-client-secret>
scope=flags:read flags:write
Response:
{
"access_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "flags:read flags:write"
}
Recommended runtime evaluation scopes:
-
flags:read -
flags:evaluate -
projects:read
Only request flags:write or projects:write when the integrating service needs to create or modify IntelliToggle resources.
Token Smoke Test
curl -sS -X POST https://api.intellitoggle.com/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=$INTELLITOGGLE_CLIENT_ID" \
--data-urlencode "client_secret=$INTELLITOGGLE_CLIENT_SECRET" \
--data-urlencode "scope=flags:read flags:evaluate"
User Authentication
The canonical user-auth contract follows the Dart Cloud Functions bootstrap model:
-
frontend authenticates with Firebase first
-
frontend sends the Firebase
idTokento the backend bootstrap endpoint -
backend responds with active and canonical tenant context
-
protected routes use
Authorization: Bearer <Firebase idToken>
POST /api/v1/auth/signup
Bootstrap a newly created Firebase account.
Request Body:
{
"idToken": "firebase_id_token",
"email": "newuser@example.com",
"password": "securepassword123"
}
POST /api/v1/auth/login
Bootstrap an existing Firebase session.
Request Body:
{
"idToken": "firebase_id_token"
}
POST /api/v1/auth/signin/microsoft
Bootstrap a federated Firebase session for the selected provider.
Request Body:
{
"idToken": "firebase_id_token",
"providerName": "google"
}
Response (200 OK):
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"uid": "firebase_uid",
"email": "user@example.com",
"tenant_id": "tenant_123",
"role": "admin"
},
"subscription": {
"plan": "standard",
"status": "active",
"billingCycle": "annual"
},
"tenants": [
{
"tenant_id": "tenant_123",
"tenant_name": "Acme",
"role": "admin"
}
],
"active_tenant_id": "tenant_123",
"active_tenant_role": "admin",
"canonical_tenant_id": "tenant_123",
"canonical_role": "admin"
}
}
POST /api/v1/auth/forgot-password
Send password reset email.
Request Body:
{
"email": "user@example.com"
}
Feature Flags
GET /api/v1/flags
List all feature flags for tenant.
Headers:
* X-Tenant-ID (required) - Tenant identifier
* X-Environment (optional, default: production) - Environment name
Response (200 OK):
[
{
"id": "flag_123",
"key": "new-checkout-flow",
"name": "New Checkout Flow",
"type": "boolean",
"enabled": true,
"defaultValue": false,
"description": "Enable the new checkout flow",
"tags": ["ui", "checkout"],
"projectId": "proj_456",
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-20T15:30:00Z"
}
]
POST /api/v1/flags
Create a new feature flag.
Headers:
* X-Tenant-ID (required)
* X-Environment (optional, default: production)
Request Body:
{
"key": "new-checkout-flow",
"name": "New Checkout Flow",
"type": "boolean",
"defaultValue": false,
"description": "Enable the new checkout flow",
"tags": ["ui", "checkout"]
}
Flag Types:
* boolean - True/false values
* string - Text values
* number - Numeric values
* json - Complex JSON objects
Response (201 Created): Returns the created flag object.
GET /api/v1/flags/{flagKey}
Get specific feature flag details.
Path Parameters:
* flagKey - Unique flag identifier
Headers:
* X-Tenant-ID (required)
* X-Environment (optional)
PATCH /api/v1/flags/{flagKey}
Update feature flag details.
Request Body:
{
"name": "Updated Name",
"description": "Updated description",
"defaultValue": true,
"tags": ["new-tag"]
}
POST /api/v1/flags/{flagKey}/evaluate
Evaluate a feature flag for specific user context.
This endpoint supports OAuth2 bearer tokens for machine-to-machine evaluation. Include X-Tenant-ID and X-Environment so the request is unambiguous.
Headers:
* Authorization: Bearer <oauth_access_token>
* X-Tenant-ID: <tenant_id>
* X-Environment: production
* Content-Type: application/json
Request Body:
{
"targetingKey": "user_123",
"attributes": {
"email": "user@example.com",
"plan": "premium",
"country": "US"
},
"environment": "production"
}
Response (200 OK):
{
"enabled": true,
"value": true,
"reason": "RULE_MATCH"
}
Flag Variations
GET /api/v1/flags/{flagKey}/variations
List all variations for a feature flag.
Response (200 OK):
[
{
"id": "var_123",
"name": "Control",
"value": false,
"description": "Control group",
"weight": 50
},
{
"id": "var_456",
"name": "Treatment",
"value": true,
"description": "Treatment group",
"weight": 50
}
]
Projects
GET /api/v1/projects
List all projects in tenant.
Headers:
* X-Tenant-ID (required)
Response (200 OK):
[
{
"id": "proj_123",
"name": "Mobile App Features",
"description": "Feature flags for mobile application",
"color": "#6366f1",
"flagCount": 15,
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-20T12:00:00Z"
}
]
POST /api/v1/projects
Create a new project.
Request Body:
{
"name": "Mobile App Features",
"description": "Feature flags for mobile application",
"color": "#6366f1"
}
Response (201 Created): Returns the created project object.
Project Flags
POST /api/v1/flags/projects/{projectId}/flags
Create a new flag within a project.
Request Body:
{
"key": "test-feature1",
"name": "Test Feature1",
"type": "boolean",
"defaultValue": false,
"description": "Test flag",
"flag_variations": [
{
"name": "Enabled",
"value": true,
"description": "Feature enabled state"
},
{
"name": "Disabled",
"value": false,
"description": "Feature disabled state"
}
]
}
Tenants
GET /api/v1/tenants
List all tenants for current user.
Response (200 OK):
[
{
"id": "tenant_123",
"name": "Acme Corporation",
"primaryEmail": "admin@acme.com",
"contactName": "John Doe",
"isSandbox": false,
"subscription": {
"plan": "premium",
"status": "active"
},
"createdAt": "2024-01-01T00:00:00Z"
}
]
POST /api/v1/tenants
Create a new tenant organization.
Request Body:
{
"name": "Acme Corporation",
"primaryEmail": "admin@acme.com",
"contactName": "John Doe",
"isSandbox": false
}
Tenant Environments
Tenant Users
GET /api/v1/tenants/{tenantId}/users
List all users in tenant.
Response (200 OK):
[
{
"userId": "user_123",
"email": "john@example.com",
"displayName": "John Doe",
"role": "admin",
"lastAccessedAt": "2024-01-20T15:30:00Z",
"createdAt": "2024-01-01T00:00:00Z"
}
]
Billing
POST /api/v1/billing/checkout
Create a Stripe checkout session for a new subscription or one-time payment.
If the tenant already has a manageable Stripe subscription, subscription
requests create a targeted Stripe Billing Portal subscription_update_confirm
session for the selected plan price instead of a generic portal session.
Stripe portal configuration must allow every switchable plan price under subscription update products, otherwise Stripe can reject the targeted plan change flow.
Headers:
* X-Tenant-ID (required)
Request Body:
{
"type": "subscription",
"planId": "standard",
"successUrl": "https://app.intellitoggle.com/membership/membership-paid",
"cancelUrl": "https://app.intellitoggle.com/membership",
"referralId": "pk_ref_123",
"promotekit_referral": "pk_ref_123",
"promoCode": "SPRING25",
"customerId": "cus_123",
"discounts": [
{
"coupon": "coupon_123"
}
]
}
Required Fields:
* type - subscription or payment
* successUrl
* cancelUrl
Subscription Checkout Fields:
* planId (required for type: "subscription")
Payment Checkout Fields:
* productId (required for type: "payment")
* amount (required for type: "payment")
Optional Fields:
* customerId
* promoCode
* discounts
* referralId - Canonical referral field
* promotekit_referral - Legacy alias still accepted
When the caller is using PromoteKit, referralId and promotekit_referral
should carry the actual PromoteKit referral value from
window.promotekit_referral or the promotekit_referral cookie.
Available Subscription Plans:
* standard - Standard plan
* enhanced - Enhanced plan
* enterprise - Enterprise plan
* sandbox - Sandbox plan
Response (200 OK):
{
"checkoutUrl": "https://checkout.stripe.com/...",
"type": "subscription"
}
POST /api/v1/billing/portal
Create Stripe customer portal session.
Request Body:
{
"returnUrl": "https://app.intellitoggle.com/billing"
}
GET /api/v1/billing/subscription
Get current subscription information.
Response (200 OK):
{
"id": "sub_123",
"plan": "premium",
"status": "active",
"currentPeriodStart": "2024-01-01T00:00:00Z",
"currentPeriodEnd": "2024-02-01T00:00:00Z",
"cancelAtPeriodEnd": false
}
OAuth Clients
POST /api/v1/oauth/clients
Create new OAuth client for API access.
Headers:
* X-Tenant-ID (required)
Request Body:
{
"name": "SDK Demo",
"scopes": [
"flags:read",
"flags:write",
"flags:evaluate",
"projects:read",
"projects:write"
]
}
Available Scopes:
* flags:read - Read flag data
* flags:write - Create and modify flags
* flags:evaluate - Evaluate flags
* projects:read - Read project data
* projects:write - Create and modify projects
Response (201 Created):
{
"clientId": "client_abc123",
"clientSecret": "secret_xyz789",
"name": "SDK Demo",
"scopes": ["flags:read", "flags:write"],
"createdAt": "2024-01-20T10:00:00Z"
}
Store the clientSecret securely. It will only be shown once.
|
Product Tours
GET /api/v1/users/{userId}/product-tours/{tourKey}
Get the status of a product tour for a user.
Path Parameters:
* userId - User identifier (e.g., usr_123)
* tourKey - Tour identifier (e.g., main-onboarding@v1)
Response (200 OK):
{
"completed": false,
"completed_at": null,
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-20T15:30:00Z"
}
Sandbox
GET /api/v1/sandbox/status
Get current sandbox environment status.
Headers:
* X-Tenant-ID (required)
Response (200 OK):
{
"active": true,
"expiresAt": "2024-02-01T00:00:00Z"
}
GET /api/v1/sandbox/indicators
Get sandbox usage indicators and metrics.
Response (200 OK):
{
"flagsUsed": 5,
"evaluations": 1000
}
GET /api/v1/sandbox/demo-data
Get demo data for sandbox environment.
Response (200 OK):
{
"flags": ["demo-flag-1", "demo-flag-2"],
"users": ["demo-user-1", "demo-user-2"]
}
Notifications
GET /api/v1/notifications
List notifications for the authenticated user.
Query Parameters:
* limit (optional, default: 20)
* offset (optional, default: 0)
* unreadOnly (optional, default: false)
Response (200 OK):
{
"notifications": [],
"totalCount": 0,
"unreadCount": 0
}
PATCH /api/v1/notifications/read-all
Mark all notifications as read for the authenticated user.
Response (200 OK):
{
"success": true,
"markedCount": 0
}
DELETE /api/v1/notifications/clear
Clear all notifications for the authenticated user.
Response (200 OK):
{
"success": true,
"clearedCount": 0
}
POST /api/v1/notifications/device-tokens
Register a device token for push notifications.
Request Body:
{
"deviceToken": "device_token_value",
"deviceName": "Chrome",
"deviceType": "web"
}
POST /api/v1/notifications/send
Send a notification (internal/admin only).
Request Body:
{
"userId": "user_123",
"tenantId": "tenant_456",
"title": "Notification title",
"body": "Optional message body",
"type": "system",
"icon": "bell",
"actionType": "link",
"referenceId": "flag_123",
"data": {
"source": "system"
}
}
Admin Endpoints
GET /api/v1/admin/users
List admin users (super_user only).
List all users across the platform (admin only).
Response (200 OK): Returns array of admin user objects.
PATCH /api/v1/admin/users/{userId}/role
Update an admin user role (super_user only).
Request Body:
{
"role": "admin"
}
Available Roles:
* viewer - Read-only admin access
* admin - Admin operator access
* super_user - Restricted Super Admin access, only for emails in ADMIN_SUPER_USER_EMAILS
POST /api/v1/admin/invitations
Invite a new admin user (super_user only).
Request Body:
{
"email": "newadmin@company.com",
"role": "admin"
}
Available Roles:
* viewer - Read-only admin access
* admin - Admin operator access
POST /admin/invite
Send invitation to new user (admin only).
Deprecated. Use POST /api/v1/admin/invitations for system admin access or POST /api/v1/tenants/{tenantId}/users for tenant invites.
Request Body (legacy):
{
"email": "newuser@company.com",
"role": "user"
}
Available Roles (legacy):
* admin - Administrator
* user - Regular user
Health & System
GET /health
Check API health status.
Response (200 OK):
{
"status": "healthy",
"timestamp": "2024-01-20T15:30:00Z"
}
Error Responses
All error responses follow RFC 9457 (Problem Details).
Error Structure
{
"type": "https://docs.example.com/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "The requested resource was not found.",
"instance": "req_01Hh88888"
}
Common Status Codes
| Code | Description |
|---|---|
200 |
Success |
201 |
Created |
204 |
No Content |
400 |
Bad Request - Invalid input |
401 |
Unauthorized - Authentication required |
403 |
Forbidden - Access denied |
404 |
Not Found - Resource doesn’t exist |
409 |
Conflict - Resource already exists |
412 |
Precondition Failed |
415 |
Unsupported Media Type |
422 |
Unprocessable Entity - Validation failed |
429 |
Too Many Requests - Rate limit exceeded |
500 |
Internal Server Error |
503 |
Service Unavailable |
Validation Errors
Validation errors (422) include detailed field-level information:
{
"type": "https://docs.example.com/errors/unprocessable-entity",
"title": "Unprocessable Entity",
"status": 422,
"detail": "Validation failed.",
"errors": {
"email": "Invalid email format",
"password": "Password must be at least 8 characters"
}
}
Rate Limiting
All endpoints are subject to rate limiting. Limits vary by subscription plan.
When rate limit is exceeded, you’ll receive a 429 response:
{
"type": "https://docs.example.com/errors/too-many-requests",
"title": "Too Many Requests",
"status": 429,
"detail": "Rate limit exceeded. Try again later."
}
Check response headers for rate limit information:
-
RateLimit-Limit- Maximum requests allowed -
RateLimit-Remaining- Remaining requests -
RateLimit-Reset- Reset time
Best Practices
Use Idempotency Keys
For critical operations (like creating subscriptions), use idempotency keys to prevent duplicate requests:
Idempotency-Key: unique-request-id-123
Handle Errors Gracefully
Always check status codes and handle errors appropriately. Don’t assume success.
Respect Rate Limits
Monitor RateLimit-Remaining header and implement exponential backoff when approaching limits.