Skip to content

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}/segments

Response: 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}/references

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