Appearance
Segments
Segments are reusable named predicates referenced from flag and config rules via the $segment operator. Same project / environment split as flags and configs; segments additionally carry an allowList and denyList of explicit target IDs.
The Segment object (joined view):
json
{
"id": "9f7a32b5-…",
"projectId": "1234abcd-…",
"envId": "5678ef01-…",
"key": "beta_testers",
"description": "Hand-picked beta participants.",
"rules": [
{ "if": { "field": "plan", "$equals": "enterprise" } }
],
"allowList": ["u_42", "u_99"],
"denyList": [],
"createdAt": "2026-04-12T10:00:00Z",
"updatedAt": "2026-04-29T14:33:00Z"
}Segment rules don't carry a value — they're predicates. Membership is allowList ∪ matched-by-rules \ denyList. See Concepts → Segments.
List segments
http
GET /api/v1/envs/{envId}/segmentsResponse: 200 → Segment[] | 404 not_found
Get a segment
http
GET /api/v1/envs/{envId}/segments/{key}Response: 200 → SegmentErrors: 403 scope_denied, 404 not_found.
Find segment references
http
GET /api/v1/envs/{envId}/segments/{key}/referencesPre-flight check before deleting a segment. Lists every flag, config, or other segment whose rules reference this one via $segment. Use this to find references before they trigger a 409 in_use on delete.
Response: 200 → SegmentReferences
json
{
"flags": [{ "key": "new-onboarding", "ruleIndex": 0 }],
"configs": [],
"segments": []
}For scoped bearer tokens, referrers are filtered to keys the caller can read.
Errors: 403 scope_denied, 404 not_found.
Create a segment
http
POST /api/v1/projects/{id}/segments
Content-Type: application/json
{
"key": "beta_testers",
"rules": [
{ "if": { "field": "plan", "$equals": "enterprise" } }
],
"allowList": ["u_42", "u_99"],
"denyList": [],
"description": "Hand-picked beta participants."
}Bearer scope: write action. Session role: editor+.
Seeds env-state into every existing environment with the supplied values in one transaction. rules, allowList, and denyList all default to [] if omitted.
Response: 201 → SegmentProjectErrors: 400 invalid_request, 403 scope_denied / approval_not_supported, 404 not_found, 409 key_collision.
Update segment metadata
http
PATCH /api/v1/projects/{id}/segments/{key}
Content-Type: application/json
{ "description": "Beta participants — Q2 cohort." }Bearer scope: write action. Session role: editor+.
Response: 200 → SegmentProjectErrors: 400 invalid_request, 403 scope_denied / approval_not_supported, 404 not_found, 412 precondition_failed.
Delete a segment
http
DELETE /api/v1/projects/{id}/segments/{key}Bearer scope: delete action. Session role: editor+.
Cascades to every environment's state — but blocks if the segment is referenced from another flag, config, or segment via $segment. Use GET /references to find references before retrying.
Response: 204 No ContentErrors: 403 scope_denied / approval_not_supported, 404 not_found, 409 in_use (with fields listing referrers as <resourceType>.<resourceKey>).
Replace environment state
http
PUT /api/v1/envs/{envId}/segments/{key}/state
Content-Type: application/json
If-Match: W/"<envStateETag>"
{
"rules": [
{ "if": { "field": "country", "$in": ["US","CA"] } }
],
"allowList": ["u_42"],
"denyList": ["u_999"]
}Bearer scope: write action. Session role: editor+.
Full-replace of (rules, allowList, denyList) for this environment. All three are required — pass [] for empty. Approval-gated tokens with rules-only deltas divert to the proposal flow.
Response: 200 → Segment (joined view) | 202 → Proposal (approval-gated divert). Errors: 400 invalid_request, 403 scope_denied / approval_not_supported, 404 not_found, 412 precondition_failed.