Skip to main content

Complete reference for all Flaggr REST API endpoints — flags, evaluation, projects, services, tokens, audit, and webhooks

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 flg_your_token

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 flg_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"
    }
  }' | jq

Bulk Evaluate

POST /api/flags/evaluate/bulk

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/bulk \
  -H "Authorization: Bearer flg_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"
    }
  }' | jq

Evaluation 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.


Flag Management

List Flags

GET /api/flags?projectId=proj-1&serviceId=web-app&environment=production

Query parameters:

ParameterTypeDescription
projectIdstringRequired. Project ID
serviceIdstringFilter by service
environmentstringdevelopment, staging, or production
limitnumberMax 100, default 50
offsetnumberOffset-based pagination
cursorstringCursor-based pagination
cursor_directionstringnext or prev
searchstringSearch flag keys and names
tagsstringComma-separated tag filter
enabledbooleanFilter by enabled state
typestringboolean, 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 flg_abc123xxxxxxxxxxxx" | jq

Create 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 flg_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
  }' | jq

Get 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. Returns the updated flag.

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": "flg_abc123..."
}

Multi-Language Examples

curl -s -X POST https://flaggr.dev/api/projects/proj-1/tokens \
  -H "Authorization: Bearer flg_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 => "flg_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:

ParameterTypeDescription
projectIdstringRequired.
actionstringFilter by action type
resourceTypestringflag, service, project, member, invitation, token
resourceIdstringSpecific resource ID
userIdstringFilter by actor
startDatestringISO date lower bound
endDatestringISO date upper bound
limitnumberMax 100
offsetnumberPagination 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 flg_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

Rate Limiting

All responses include rate limit headers:

HeaderDescription
RateLimit-LimitTotal requests allowed in window
RateLimit-RemainingRemaining requests
RateLimit-ResetUnix 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'"
}
StatusDescription
400Bad request — invalid parameters or validation failure
401Unauthorized — missing or invalid authentication
403Forbidden — insufficient permissions
404Not found
409Conflict — duplicate resource
429Rate limited
500Internal server error
503Service unavailable

Request Size Limits

EndpointMax Size
Flag create/update256 KB
Flag evaluation64 KB
Bulk operations25.6 MB