Complete reference for all Flaggr REST API endpoints — flags, evaluation, projects, services, tokens, audit, and webhooks
Last updated October 6, 2026
REST API Reference
Base URL: https://flaggr.dev (or your self-hosted instance).
All endpoints accept and return application/json. State-changing requests (POST, PATCH, DELETE) require a CSRF token in the X-CSRF-Token header.
Authentication
Bearer Token
Authorization: Bearer fgr_your_token
Session Cookie
Firebase session cookies are sent automatically by the dashboard.
Get CSRF Token
GET /api/csrf-token
{ "token": "abc123", "headerName": "x-csrf-token" }Flag Evaluation
Evaluate a Single Flag
POST /api/flags/evaluate
Evaluates a flag against the provided context. This is the primary evaluation endpoint.
Request:
{
"flagKey": "checkout-v2",
"serviceId": "web-app",
"environment": "production",
"defaultValue": false,
"context": {
"targetingKey": "user-123",
"email": "alice@example.com",
"plan": "enterprise"
}
}Response:
{
"flagKey": "checkout-v2",
"value": true,
"reason": "TARGETING_MATCH",
"variant": "enabled",
"_debug": {
"timings": {
"rateLimit": 2,
"validation": 1,
"cacheGet": 0.5,
"evaluate": 3
},
"cacheHit": false,
"totalMs": 12
}
}Auth: API token (read) OR session. Public flags can be evaluated without auth.
Rate limits: 1,000/min (IP) · 5,000/min (token) · 10,000/min (service)
Multi-Language Examples
curl -s -X POST https://flaggr.dev/api/flags/evaluate \
-H "Authorization: Bearer fgr_abc123xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"flagKey": "checkout-v2",
"serviceId": "web-app",
"environment": "production",
"defaultValue": false,
"context": {
"targetingKey": "user-123",
"email": "alice@example.com",
"plan": "enterprise"
}
}' | jqBulk Evaluate
POST /api/flags/evaluate/batch
Evaluates multiple flags in a single request. Use this to reduce round-trips when your application needs several flags at once.
Request:
{
"serviceId": "web-app",
"environment": "production",
"flags": [
{ "flagKey": "checkout-v2", "defaultValue": false },
{ "flagKey": "dark-mode", "defaultValue": false },
{ "flagKey": "new-pricing", "defaultValue": "off" }
],
"context": {
"targetingKey": "user-123",
"plan": "enterprise"
}
}Response:
{
"results": [
{ "flagKey": "checkout-v2", "value": true, "reason": "TARGETING_MATCH", "variant": "enabled" },
{ "flagKey": "dark-mode", "value": false, "reason": "DEFAULT" },
{ "flagKey": "new-pricing", "value": "tier-b", "reason": "VARIANT", "variant": "tier-b" }
]
}Multi-Language Examples
curl -s -X POST https://flaggr.dev/api/flags/evaluate/batch \
-H "Authorization: Bearer fgr_abc123xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"serviceId": "web-app",
"environment": "production",
"flags": [
{ "flagKey": "checkout-v2", "defaultValue": false },
{ "flagKey": "dark-mode", "defaultValue": false },
{ "flagKey": "new-pricing", "defaultValue": "off" }
],
"context": {
"targetingKey": "user-123",
"plan": "enterprise"
}
}' | jqEvaluation Logs
GET /api/evaluations?flagKey=checkout-v2&serviceId=web-app&limit=100&since=2025-01-01
Returns recent evaluation events for debugging.
DELETE /api/evaluations?flagKey=checkout-v2
Clears evaluation logs.
Public Demo Service
The pixel-grid service (4,096 boolean flags — a 64×64 grid where flag
px-N is cell N) is a designated public demo service. The standard
core endpoints below work unauthenticated against it — no token required.
This is what powers the landing-page demo; it uses no special transport.
List the grid
GET /api/flags?serviceId=pixel-grid&environment=development&limit=4096
When serviceId is a public demo service, projectId may be omitted and
the page-size cap relaxes to 4,096 (the whole grid in one call). For every
other service, projectId and a read-scoped token are still required.
Sparse fieldsets — pass ?fields=key,enabled to project each flag to
just the named fields (whitelist: key, name, description, type,
enabled, defaultValue, serviceId, environment, tags, variants,
targeting, isPublic, createdAt, updatedAt). For the full grid this
cuts the response from ~2.3MB of flag documents to ~140KB. Works on
authenticated lists too.
Conditional requests — public demo list responses carry a weak ETag
over the result set. Send it back as If-None-Match; when nothing changed
the response is 304 Not Modified with an empty body — the poll path in
the demo does this so unchanged 6s ticks cost a roundtrip, not a download.
Evaluate the grid
POST /api/flags/evaluate/batch
{
"serviceId": "pixel-grid",
"environment": "development",
"flags": [{ "key": "px-0", "defaultValue": false }, "..."]
}Public demo services may batch up to 4,096 flags per request (the normal
cap is 100) and skip token auth. All flags in the service are also
isPublic, so POST /api/flags/evaluate works flag-by-flag too.
Stream updates
GET /api/flags/stream?serviceId=pixel-grid&environment=development
The standard SSE stream, open without a token for demo services. Each
message is a data: JSON payload — type: "connected" on open, then
type: "flag-update" per mutated flag with the full flag object included
(flag.enabled, flag.updatedAt, …).
Write to the grid
PATCH /api/flags/bulk
{
"flags": [
{
"key": "px-0",
"serviceId": "pixel-grid",
"environment": "development",
"updates": { "enabled": true }
}
]
}When every serviceId in the request is a public demo service, bulk
updates run unauthenticated — the demo grid is intentionally shared and
mutable. Public writes are constrained:
- Only
updates.enabledis applied; all other fields are ignored. - Up to 4,096 flag updates per request (normal cap is 100).
- One write per IP per 2 seconds.
- Writes are attributed to a
public-demoactor in the audit log.
Summary responses — PATCH /api/flags/bulk?summary=true returns only
{success,total,succeeded,failed} instead of the per-flag result array
(~50B vs ~2.6MB for a full-grid write). Works on authenticated calls too.
Any non-demo service in the same request reverts to the normal CSRF + write-token requirements — public access never crosses service boundaries.
Flag Management
List Flags
GET /api/flags?projectId=proj-1&serviceId=web-app&environment=production
Query parameters:
| Parameter | Type | Description |
|---|---|---|
projectId | string | Required. Project ID |
serviceId | string | Filter by service |
environment | string | development, staging, or production |
limit | number | Max 100, default 50 |
offset | number | Offset-based pagination |
cursor | string | Cursor-based pagination |
cursor_direction | string | next or prev |
search | string | Search flag keys and names |
tags | string | Comma-separated tag filter |
enabled | boolean | Filter by enabled state |
type | string | boolean, string, number, or object |
Response:
{
"flags": [...],
"total": 42,
"limit": 50,
"offset": 0,
"hasMore": false,
"nextCursor": null,
"prevCursor": null
}Multi-Language Examples
curl -s "https://flaggr.dev/api/flags?projectId=proj-1&serviceId=web-app&environment=production&limit=10" \
-H "Authorization: Bearer fgr_abc123xxxxxxxxxxxx" | jqCreate Flag
POST /api/flags
{
"key": "checkout-v2",
"name": "Checkout V2",
"description": "New checkout flow",
"type": "boolean",
"enabled": false,
"defaultValue": false,
"serviceId": "web-app",
"environment": "production",
"tags": ["checkout", "experiment"],
"variants": [
{ "name": "control", "value": false, "weight": 50 },
{ "name": "treatment", "value": true, "weight": 50 }
],
"targeting": [],
"isPublic": false
}Returns 201 with the created flag. Triggers flag.created event (Pub/Sub + webhooks), saves version snapshot, and writes audit log.
Multi-Language Examples
curl -s -X POST https://flaggr.dev/api/flags \
-H "Authorization: Bearer fgr_abc123xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: $CSRF_TOKEN" \
-d '{
"key": "checkout-v2",
"name": "Checkout V2",
"description": "New checkout flow",
"type": "boolean",
"enabled": false,
"defaultValue": false,
"serviceId": "web-app",
"environment": "production",
"tags": ["checkout", "experiment"],
"variants": [
{ "name": "control", "value": false, "weight": 50 },
{ "name": "treatment", "value": true, "weight": 50 }
],
"targeting": [],
"isPublic": false
}' | jqGet Flag
GET /api/flags/{key}?serviceId=web-app&environment=production
Update Flag
PATCH /api/flags/{key}?serviceId=web-app&environment=production
Send a partial update — only include fields you want to change:
{
"enabled": true,
"targeting": [
{
"id": "beta-users",
"conditions": [
{ "property": "betaUser", "operator": "equals", "value": true }
],
"value": true
}
]
}Delete Flag
DELETE /api/flags/{key}?serviceId=web-app&environment=production
Toggle Flag
POST /api/flags/{key}/toggle?serviceId=web-app&environment=production
Flips the enabled state (or explicitly sets it when passing {"enabled": boolean} in the JSON body). Broadcasts real-time updates over SSE, records a version snapshot and audit log entry, and purges Redis cache keys asynchronously via serverless durability lifecycles.
Post-Toggle Safety & Drift Analysis
GET /api/flags/{key}/toggle-impact?serviceId=web-app&environment=production&range=24h&windowMinutes=30
Evaluates post-toggle safety, health, and performance drift by comparing metrics before and after the latest toggle event.
Query parameters:
| Parameter | Required | Description |
|---|---|---|
serviceId | Yes | Service identifier |
environment | No | Environment filter (e.g. production, staging, development) |
range | No | Time range for evaluation discovery: 1h, 24h, 7d, 30d (default 24h) |
windowMinutes | No | Comparison window duration before/after toggle (e.g. 15, 30, 60) |
Response:
{
"flagKey": "checkout-v2",
"serviceId": "web-app",
"environment": "production",
"range": "24h",
"impact": {
"hasRecentToggle": true,
"latestToggle": {
"id": "audit-f9e4a8b2",
"timestamp": "2026-09-12T08:00:00.000Z",
"timestampMs": 1789200000000,
"actor": "release-engineer@flaggr.dev",
"transition": { "from": false, "to": true },
"environment": "production",
"durationMs": 42
},
"healthStatus": "healthy",
"windowMinutes": 30,
"before": {
"evaluations": 1200,
"errors": 2,
"errorRate": 0.0017,
"avgLatencyMs": 1.5,
"p99LatencyMs": 4.2
},
"after": {
"evaluations": 1250,
"errors": 1,
"errorRate": 0.0008,
"avgLatencyMs": 1.48,
"p99LatencyMs": 4.15
},
"delta": {
"errorRateDelta": -0.0009,
"latencyP99DeltaMs": -0.05,
"evaluationsRatio": 1.04
},
"recommendation": "Healthy: Post-toggle metrics are stable with no significant error or latency regression."
},
"recentToggles": [
{
"id": "audit-f9e4a8b2",
"timestamp": "2026-09-12T08:00:00.000Z",
"timestampMs": 1789200000000,
"actor": "release-engineer@flaggr.dev",
"transition": { "from": false, "to": true },
"environment": "production",
"durationMs": 42
}
]
}Flag Evaluation Metrics & Time Series
GET /api/flags/{key}/metrics?serviceId=web-app&environment=production&range=24h
Returns comprehensive evaluation metrics, real-time rates, value and reason breakdowns, time-series data, and correlated toggle impact analysis.
Query parameters:
| Parameter | Required | Description |
|---|---|---|
serviceId | Yes | Service identifier |
environment | No | Environment filter |
range | No | Time range: 1h, 24h, 7d, 30d (default 24h) |
Response:
{
"flagKey": "checkout-v2",
"serviceId": "web-app",
"environment": "production",
"source": "memory",
"range": {
"start": 1789113600000,
"end": 1789200000000,
"rangeLabel": "24h",
"minutes": 1440
},
"summary": {
"totalEvaluations": 48500,
"totalErrors": 24,
"errorRate": 0.0005,
"avgLatencyMs": 1.42,
"p50LatencyMs": 1.1,
"p95LatencyMs": 3.8,
"p99LatencyMs": 6.2,
"evaluationsPerMinute": 33.68,
"evaluationsPerSecond": 0.56
},
"realtime": {
"evaluationsPerSecond": 1.2,
"evaluationsPerMinute": 72,
"evaluationsLastMinute": 72,
"evaluationsLast5Min": 340,
"errorRateLastMinute": 0,
"trend": "stable",
"lastEvaluatedAt": "2026-09-12T08:15:00.000Z",
"topReason": "TARGETING_MATCH"
},
"toggleImpact": { ... },
"recentToggles": [ ... ],
"reasonBreakdown": {
"TARGETING_MATCH": 38200,
"DEFAULT_VALUE": 10276,
"ERROR": 24
},
"valueBreakdown": {
"true": 38200,
"false": 10300
},
"timeSeries": [
{
"timestamp": 1789113600000,
"evaluations": 2040,
"errors": 1,
"avgLatencyMs": 1.38,
"p50LatencyMs": 1.05,
"p95LatencyMs": 3.5,
"p99LatencyMs": 5.9
}
]
}Automated Guardrail Circuit Breaking & Rollback
POST /api/flags/{key}/auto-rollback
GET /api/flags/{key}/auto-rollback?serviceId=web-app&environment=production
Evaluates post-toggle safety drift and automatically reverts the feature flag to its previous version snapshot if health metrics are degraded. Also supports dry-run preview mode.
Request body (or query parameters):
| Field | Type | Description |
|---|---|---|
serviceId | string | Service identifier (required) |
environment | string | Target environment (default: production) |
dryRun | boolean | If true, returns what action would be taken without mutating flag state |
maxErrorRateDelta | number | Maximum allowed error rate increase before tripping (default: 0.02 for +2%) |
maxLatencyDeltaMs | number | Maximum allowed P99 latency increase in ms (default: 200) |
windowMinutes | number | Pre/post toggle evaluation window in minutes |
Response:
{
"flagKey": "checkout-v2",
"serviceId": "web-app",
"environment": "production",
"actionTaken": "rolled_back",
"reason": "Rollback completed: Guardrails tripped due to error rate surge +5.00%. Flag reverted to version 2.",
"tripped": true,
"targetVersionNumber": 2,
"alertNotifiedChannels": ["ch-slack-prod", "ch-pagerduty"]
}Project Stale Flags & Technical Debt Analysis
GET /api/projects/{id}/stale-flags
Scans all flags in a project to discover candidates for codebase cleanup, archiving, or deletion based on evaluation inactivity and 100% rollout duration.
Response:
{
"total": 5,
"staleCount": 2,
"inactiveCount": 1,
"launchedCount": 1,
"potentialTechDebtFlags": 3,
"reports": [
{
"flagKey": "legacy-auth",
"serviceId": "svc-auth",
"environment": "production",
"status": "stale",
"category": "stale_rolled_out",
"daysInactive": 0,
"daysSinceLastMutation": 45,
"rolloutPercentage": 100,
"stalenessScore": 90,
"recommendation": "100% rolled out for 45 days. Candidate for permanent code migration.",
"codeRemovalAdvice": "Replace flag('legacy-auth') check with true branch; delete fallback code."
}
]
}Organization Alert Channels
GET /api/orgs/{orgId}/alert-channels
POST /api/orgs/{orgId}/alert-channels
DELETE /api/orgs/{orgId}/alert-channels/{channelId}
POST /api/orgs/{orgId}/alert-channels/{channelId}/test
Manage organization-wide alert destinations (Slack, Discord, PagerDuty, Email, Webhook) automatically inherited by all projects in the organization.
SDK Ingest & Telemetry Analytics
POST /api/analytics/sdk-telemetry
GET /api/analytics/sdk-telemetry?serviceId=web-app&environment=production&range=24h
Ingests batched client-side telemetry (evaluations, Core Web Vitals, and errors) and provides aggregated analytics reports correlated with active feature flags.
Ingest SDK Telemetry (POST)
Request Body:
{
"serviceId": "web-app",
"environment": "production",
"summaries": [
{
"flagKey": "checkout-v2",
"variant": "enabled",
"evaluations": 1420,
"cacheHits": 1395,
"cacheMisses": 25,
"avgLatencyMs": 0.12
}
],
"webVitals": [
{
"name": "LCP",
"value": 1420.5,
"rating": "good",
"activeFlags": { "checkout-v2": "enabled" },
"timestamp": 1718000000000
}
],
"errors": [
{
"message": "Payment gateway timeout",
"stack": "Error: Payment gateway timeout\n at submitPayment (checkout.js:142)",
"activeFlags": { "checkout-v2": "enabled" },
"timestamp": 1718000005000
}
],
"diagnostics": {
"totalEvaluations": 1420,
"cacheHits": 1395,
"cacheHitRatio": 0.982,
"trackedFlagsCount": 1
}
}Response (200 OK):
{
"success": true,
"processed": {
"evaluations": 1420,
"webVitals": 1,
"errors": 1
}
}Query Aggregated Telemetry Report (GET)
Query Parameters:
serviceId(optional): Filter by service ID.environment(optional): Filter by environment.flagKey(optional): Filter by specific flag key.range(optional): Time range (1h,6h,24h,7d, default:24h).
Response (200 OK):
{
"range": "24h",
"totalEvaluations": 45200,
"cacheHitRatio": 0.985,
"evaluationSummaries": [
{
"flagKey": "checkout-v2",
"evaluations": 25400,
"cacheHits": 25100,
"cacheMisses": 300,
"avgLatencyMs": 0.14
}
],
"webVitals": [
{
"metric": "LCP",
"count": 3120,
"p75": 1640.2,
"ratings": { "good": 2800, "needs-improvement": 280, "poor": 40 }
}
],
"topErrors": [
{
"message": "Payment gateway timeout",
"count": 4,
"firstSeen": "2026-09-12T10:15:00.000Z",
"lastSeen": "2026-09-12T11:45:00.000Z",
"correlatedFlags": ["checkout-v2"]
}
]
}Flag Version History
GET /api/flags/{key}/history?serviceId=web-app&limit=20&offset=0
{
"versions": [...],
"total": 15,
"hasMore": false
}Rollback to Version
POST /api/flags/{key}/rollback/{version}
Restores the flag to a previous version snapshot.
Bulk Operations
All bulk endpoints accept arrays of flag operations and return per-item results.
Bulk Create
POST /api/flags/bulk
{
"flags": [
{ "key": "flag-a", "name": "Flag A", "type": "boolean", "serviceId": "web-app", "defaultValue": false },
{ "key": "flag-b", "name": "Flag B", "type": "string", "serviceId": "web-app", "defaultValue": "off" }
]
}Bulk Update
PATCH /api/flags/bulk
{
"flags": [
{ "key": "flag-a", "serviceId": "web-app", "environment": "production", "updates": { "enabled": true } },
{ "key": "flag-b", "serviceId": "web-app", "environment": "production", "updates": { "enabled": false } }
]
}Bulk Delete
DELETE /api/flags/bulk
{
"flags": [
{ "key": "flag-a", "serviceId": "web-app", "environment": "production" },
{ "key": "flag-b", "serviceId": "web-app", "environment": "production" }
]
}Response (all bulk):
{
"success": true,
"total": 2,
"succeeded": 2,
"failed": 0,
"results": [
{ "key": "flag-a", "status": "success", "flag": {...} },
{ "key": "flag-b", "status": "success", "flag": {...} }
]
}Status codes: 201 (all succeed on create), 200 (all succeed on update/delete), 207 (mixed results).
Export & Import
Export Flags
GET /api/flags/export?projectId=proj-1&serviceId=web-app&format=json&includeDisabled=true
Returns a downloadable JSON file:
{
"version": "1.0",
"exportedAt": "2025-07-20T10:00:00Z",
"projectId": "proj-1",
"flagCount": 42,
"flags": [...]
}Import Flags
POST /api/flags/import
Upload an exported JSON file to restore flags.
Projects
List Projects
GET /api/projects
Returns all projects the authenticated user has access to, including their role.
Create Project
POST /api/projects
{
"name": "My Project",
"description": "Feature flags for the platform",
"slug": "my-project",
"tags": ["platform"]
}The creator is automatically assigned the owner role.
Get Project
GET /api/projects/{id}
Get Project by Slug
GET /api/projects/by-slug/{slug}
Update Project
PATCH /api/projects/{id}
Requires manage_settings permission. Only owners can change slugs.
Delete Project
DELETE /api/projects/{id}
Requires delete_project permission. Cascade-deletes all resources.
Services
List Services
GET /api/services?projectId=proj-1&limit=50&search=web
Create Service
POST /api/services
{
"projectId": "proj-1",
"name": "Web App",
"description": "Frontend web application",
"tags": ["frontend"]
}Get / Update / Delete Service
GET /api/services/{id}
PATCH /api/services/{id}
DELETE /api/services/{id}
GET /api/services/by-slug/{slug}
Team Members
List Members
GET /api/projects/{id}/members
Add Member
POST /api/projects/{id}/members
{ "userId": "user-456", "role": "member" }Roles: owner, admin, member, viewer.
Update / Remove Member
PATCH /api/projects/{id}/members/{memberId}
DELETE /api/projects/{id}/members/{memberId}
Invitations
List Invitations
GET /api/projects/{id}/invitations
Create Invitation
POST /api/projects/{id}/invitations
{ "email": "bob@example.com", "role": "member" }Invitations expire after 7 days. Cannot invite as owner.
API Tokens
List Project Tokens
GET /api/projects/{id}/tokens
Create Opaque Token
POST /api/projects/{id}/tokens
{
"name": "CI Read Token",
"permissions": { "read": true, "write": false, "delete": false },
"expiresAt": "2026-12-31T00:00:00Z"
}The plain token value is only returned on creation:
{
"token": { "id": "...", "name": "CI Read Token", ... },
"value": "fgr_abc123..."
}Multi-Language Examples
curl -s -X POST https://flaggr.dev/api/projects/proj-1/tokens \
-H "Authorization: Bearer fgr_abc123xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "X-CSRF-Token: $CSRF_TOKEN" \
-d '{
"name": "CI Read Token",
"permissions": { "read": true, "write": false, "delete": false },
"expiresAt": "2026-12-31T00:00:00Z"
}' | jq
# Save the token value — it is only shown once
# .value => "fgr_abc123..."Create JWT Token
POST /api/projects/{id}/tokens
{
"name": "Service JWT",
"scopes": ["read", "write"]
}Returns accessToken, refreshToken, and expiration timestamps.
Refresh JWT
POST /api/projects/{id}/tokens/refresh
Authorization: Bearer {refreshToken}
List My Tokens
GET /api/users/me/tokens
Returns all tokens created by the authenticated user across all projects.
Revoke Token
DELETE /api/projects/{id}/tokens/{tokenId}
Audit Logs
Query Audit Logs
GET /api/audit?projectId=proj-1&action=flag.update&limit=50
Query parameters:
| Parameter | Type | Description |
|---|---|---|
projectId | string | Required. |
action | string | Filter by action type |
resourceType | string | flag, service, project, member, invitation, token |
resourceId | string | Specific resource ID |
userId | string | Filter by actor |
startDate | string | ISO date lower bound |
endDate | string | ISO date upper bound |
limit | number | Max 100 |
offset | number | Pagination offset |
Actions: flag.create, flag.update, flag.delete, flag.toggle, service.create, service.update, service.delete, member.add, member.remove, member.role_change, invitation.create, invitation.accept, invitation.cancel, token.create, token.update, token.revoke
Response:
{
"logs": [
{
"id": "log-1",
"projectId": "proj-1",
"userId": "user-123",
"action": "flag.update",
"resourceType": "flag",
"resourceId": "checkout-v2",
"resourceName": "Checkout V2",
"before": { "enabled": false },
"after": { "enabled": true },
"changes": [
{ "field": "enabled", "oldValue": false, "newValue": true }
],
"metadata": {},
"timestamp": "2025-07-20T10:30:00Z",
"ipAddress": "203.0.113.1",
"userAgent": "Mozilla/5.0..."
}
],
"total": 150,
"limit": 50,
"offset": 0
}Webhooks
List Webhooks
GET /api/webhooks
Register Webhook
POST /api/webhooks
{
"url": "https://example.com/webhook",
"secret": "whsec_your_secret",
"events": ["flag.created", "flag.updated", "flag.deleted", "flag.toggled"],
"active": true
}Update / Delete Webhook
PATCH /api/webhooks/{id}
DELETE /api/webhooks/{id}
See Webhooks Guide for payload format and signature verification.
Health Checks
Application Health
GET /api/health
{
"status": "healthy",
"timestamp": "2025-07-20T10:00:00Z",
"version": {
"app": "1.0.0",
"commit": "abc123",
"environment": "production"
},
"cache": {
"backend": "redis",
"readCache": { "working": true, "testTime": 2 },
"writeCache": { "working": true, "testTime": 3 }
},
"storage": { "backend": "firestore" }
}Admin Health
GET /api/health/admin
Detailed health including storage, cache, and auth subsystem status.
Evaluation Health
GET /api/health/evaluation
Validates the flag evaluation pipeline is functional.
Alerts
Get Alert Status
GET /api/alerts
GET /api/alerts?firing=true
{
"status": "ok",
"firingCount": 0,
"alerts": [
{
"name": "HighErrorRate",
"status": "resolved",
"severity": "critical",
"description": "Error rate exceeds 1%",
"value": 0.2,
"threshold": 1
}
],
"evaluatedAt": "2025-07-20T10:00:00Z"
}Streaming
Connect Stream (SSE)
GET /api/connect/stream?serviceId=web-app&environment=production&clientId=client-1
Returns a text/event-stream with real-time flag change events. See Protocols for details.
Multi-Language Examples
# SSE streams stay open — press Ctrl-C to stop
curl -N "https://flaggr.dev/api/flags/stream?serviceId=web-app" \
-H "Authorization: Bearer fgr_abc123xxxxxxxxxxxx" \
-H "Accept: text/event-stream"Legacy Stream
GET /api/flags/stream?serviceId=web-app
Backward-compatible SSE stream.
Connect Protocol
Evaluate (Connect)
POST /api/connect/evaluate
Uses structured Connect protocol format with protobuf-style values. See Protocols.
Bulk Evaluate (Connect)
POST /api/connect/bulk-evaluate
OFREP v1 — Single
POST /api/ofrep/v1/evaluate/flags/{key}
X-Service-Id: web-app
OFREP v1 — Bulk
POST /api/ofrep/v1/evaluate/flags
X-Service-Id: web-app
OFREP Metadata
GET /api/ofrep/v1/metadata
Closed-Loop Canary Rollout Pipelines
Automated progressive delivery pipelines with metric health gates, minimum soak periods, and automated circuit-breaker rollbacks.
Start Canary Pipeline
POST /api/flags/[key]/canary
{
"serviceId": "web-app",
"environment": "production",
"initialRolloutPercent": 5,
"targetRolloutPercent": 100,
"rampStepPercent": 20,
"soakPeriodMinutes": 30,
"errorRateGateDelta": 0.01,
"latencyGateDeltaMs": 50,
"autoRollbackOnBreach": true
}Get Canary Pipeline Status
GET /api/flags/[key]/canary?serviceId=web-app&environment=production
Returns the current active stage, completed stages, remaining soak time, and real-time metric health assessment.
Advance Canary Stage
POST /api/flags/[key]/canary/advance
{
"serviceId": "web-app",
"environment": "production",
"force": false
}Abort Canary Pipeline
POST /api/flags/[key]/canary/abort
{
"serviceId": "web-app",
"environment": "production",
"reason": "Elevated P99 latency during 25% stage"
}Targeting Rule Explanation & Blast-Radius Simulator
Explain Flag Evaluation
POST /api/flags/[key]/explain
Step-by-step diagnostic evaluation debugger explaining clause-by-clause why a user context resolved to a specific variant.
{
"serviceId": "web-app",
"environment": "production",
"context": {
"targetingKey": "user-42",
"tier": "enterprise",
"country": "US"
}
}Simulate Blast-Radius
POST /api/flags/[key]/simulate
Counterfactual blast-radius simulation comparing current baseline flag vs proposed candidate flag across synthetic user cohorts.
{
"serviceId": "web-app",
"environment": "production",
"cohortSize": 200,
"candidateFlag": {
"targeting": [
{
"id": "new-rule",
"conditions": [{ "property": "tier", "operator": "equals", "value": "enterprise" }],
"rolloutPercentage": 100,
"value": true
}
]
}
}Adaptive Multi-Armed Bandits
Bayesian Thompson Sampling and Epsilon-Greedy dynamic traffic weight reallocation with automated statistical stopping rules.
List Bandit Experiments
GET /api/experiments/bandit?projectId=proj-1&serviceId=web-app
Create Bandit Experiment
POST /api/experiments/bandit
{
"name": "Checkout CTA Optimization",
"projectId": "proj-1",
"serviceId": "web-app",
"flagKey": "checkout-cta",
"algorithm": "thompson_sampling",
"minExplorationFloor": 5,
"minSampleSizePerVariant": 100,
"confidenceThreshold": 0.95,
"autoRolloutWinner": true
}Get Bandit Status
GET /api/experiments/[id]/bandit-status
Reallocate Bandit Traffic
POST /api/experiments/[id]/reallocate
Rebalances variant traffic allocations according to posterior win probabilities. If the statistical confidence threshold is met, automatically promotes the winner to 100% rollout.
Record Bandit Reward
POST /api/experiments/[id]/reward
{
"variantName": "variant-b",
"converted": true
}Dynamic Audience Cohorts & Membership
Evaluate Cohort Membership
POST /api/projects/[id]/cohorts/[cohortId]/evaluate
{
"userId": "user-123",
"context": {
"email": "alice@corp.com",
"country": "AU"
}
}Flag Triggers (CI/CD)
Scoped, revocable URLs that apply a flag action — designed for pipelines ("enable the flag when deploy completes"). The token is the capability: POST the URL with no auth headers.
Create a Trigger
POST /api/flags/{key}/triggers
Authorization: Bearer flg_...
{
"serviceId": "web",
"environment": "production",
"action": "enable", // enable | disable | toggle
"name": "deploy-complete"
}
Returns the trigger url and raw token once — only the SHA-256 hash is stored. Triggers are also managed from the flag's Triggers tab in the console.
Execute a Trigger
POST /api/triggers/{token} // no auth — the token is the capability
Applies the action through the full mutation path (version snapshot, audit as trigger:{name}, SSE fanout, cache invalidation). Rate-limited to 30 executions/minute per token. 404 for unknown and revoked tokens.
List / Revoke
GET /api/flags/{key}/triggers?serviceId=web
DELETE /api/flags/{key}/triggers/{triggerId}?serviceId=web
Watching Flags & Notifications
Follow a flag to see its mutations in the console notifications bell.
POST /api/flags/{key}/watch { "serviceId": "web", "environment": "production" }
DELETE /api/flags/{key}/watch?serviceId=web&environment=production
GET /api/flags/{key}/watch?serviceId=web&environment=production // { "watching": true }
GET /api/notifications // recent audit events on watched flags + unreadCount
POST /api/notifications // mark all read
Evaluation Contexts
GET /api/contexts?serviceId=web&environment=production
GET /api/contexts?serviceId=web&key=user-alice-1 // one context's flag→value map
Recent evaluation contexts grouped by targetingKey — attributes, eval count, and what each flag resolved to. Backed by the in-memory evaluation ring (last ~1,000 evals per instance).
Rate Limiting
All responses include rate limit headers:
| Header | Description |
|---|---|
RateLimit-Limit | Total requests allowed in window |
RateLimit-Remaining | Remaining requests |
RateLimit-Reset | Unix timestamp when limit resets |
Limits: 1,000/min per IP, 5,000/min per API token, 10,000/min per service.
When rate limited, you'll receive a 429 Too Many Requests response.
Error Responses
All errors follow a consistent format:
{
"error": "Not Found",
"message": "Flag 'checkout-v3' not found in service 'web-app'"
}| Status | Description |
|---|---|
400 | Bad request — invalid parameters or validation failure |
401 | Unauthorized — missing or invalid authentication |
403 | Forbidden — insufficient permissions |
404 | Not found |
409 | Conflict — duplicate resource |
429 | Rate limited |
500 | Internal server error |
503 | Service unavailable |
Request Size Limits
| Endpoint | Max Size |
|---|---|
| Flag create/update | 256 KB |
| Flag evaluation | 64 KB |
| Bulk operations | 25.6 MB |