Skip to content

Gets evaluation counts for the flag in one environment.

GET
/api/v1/orgs/{org}/projects/{project}/flags/{flag}/environments/{env}/evaluations
curl --request GET \
--url 'https://api.featureflip.io/api/v1/orgs/example/projects/example/flags/example/environments/example/evaluations?days=7' \
--header 'Authorization: <Authorization>'

Counts every evaluation over the last days UTC days (7, 30 or 90; default 7), starting no earlier than the flag’s creation day. These are evaluation counts, not unique users. They come from SDK-reported events, so an environment whose SDKs report none reads zero: no evaluations reported, not necessarily no traffic. Sources are ordered live rules in evaluation order, then deleted rules, then fallthrough, off, prerequisite, error, notFound and unknown. On a percentage-rollout rule, rollout.flagged is true when the served split is statistically off the configured weights (p < 0.001 and at least 2 percentage points off for some variation).

org
required
string
project
required
string
flag
required
string
env
required
string
days
integer format: int32
default: 7
Allowed values: 7 30 90

OK

Media type application/json

What a flag served in one environment over the window, returned by GET .../flags/{flag}/environments/{env}/evaluations (#4225). These are evaluation counts, not unique users. They come from SDK-reported events, so an environment whose SDKs report none reads zero: no evaluations reported, not necessarily no traffic. The public counterpart of FlagEvaluationAnalyticsDto, keyed by environment key instead of id and without the dashboard’s daily series.

object
environmentKey
required

The environment’s key.

string
days
required

The window requested: 7, 30 or 90.

integer format: int32
fromUtc
required

Start of the window: UTC midnight days - 1 days ago, or the flag’s creation day if later.

string format: date-time
toUtc
required

When the counts were read.

string format: date-time
totalCount
required

Evaluations in the window. Evaluation counts, not unique users.

integer format: int64
lastEvaluatedAtUtc

The last reported evaluation, or null if none was reported.

string format: date-time
nullable
variations
required

Evaluations per variation over the window.

Array<object>

One variation’s evaluations.

object
variationKey

The variation served, or null for evaluations recorded without one.

string
nullable
name

The variation’s name, or null when the key no longer matches one of the flag’s variations.

string
nullable
exists
required

False when the key no longer matches one of the flag’s variations.

boolean
count
required

Evaluations that served this variation.

integer format: int64
share
required

Count as a fraction (0 to 1) of the parent total: the window’s total, or for a source’s variations that source’s count. 0 when the parent total is 0.

number format: double
sources
required

Evaluations per part of the targeting that served them: live rules in evaluation order, then deleted rules, then fallthrough, off, prerequisite, error, notFound and unknown. A live percentage-rollout rule is always listed, with a count of 0 and no variations when it served nothing in the window, so its rollout check (and rollout.unreached) has a row.

Array<object>

The evaluations one part of the targeting served.

object
source
required

One of rule, fallthrough, off, prerequisite, error, notFound or unknown (an SDK that reports no reason, or evaluations recorded before sources were). Allowed values: rule, fallthrough, off, prerequisite, error, notFound, unknown.

string
Allowed values: rule fallthrough off prerequisite error notFound unknown
ruleId

For a rule, its id (rules have no key). Null otherwise, or when the SDK didn’t say which rule.

string format: uuid
nullable
ruleLabel

For a live rule, its description or a generated label. Null otherwise.

string
nullable
ruleExists
required

False when the rule is no longer in the environment’s targeting.

boolean
count
required

Evaluations this source served.

integer format: int64
share
required

Count as a fraction (0 to 1) of all sources’ counts combined.

number format: double
variations
required

What this source served, with shares of this source’s count.

Array<object>

One variation’s evaluations.

object
variationKey

The variation served, or null for evaluations recorded without one.

string
nullable
name

The variation’s name, or null when the key no longer matches one of the flag’s variations.

string
nullable
exists
required

False when the key no longer matches one of the flag’s variations.

boolean
count
required

Evaluations that served this variation.

integer format: int64
share
required

Count as a fraction (0 to 1) of the parent total: the window’s total, or for a source’s variations that source’s count. 0 when the parent total is 0.

number format: double
rollout

A percentage-rollout rule’s configured split beside a sample-ratio check of what it served.

object
configured
required

The configured weights, in percent; they sum to 100.

Array<object>

A variation’s configured share of a rollout rule.

object
variationKey
required

The variation’s key.

string
name

The variation’s name, or null when the key no longer matches one of the flag’s variations.

string
nullable
weight
required

Percent of the rule’s traffic.

integer format: int32
splitChangedAtUtc

The last time the split may have changed (the rule was edited, or a variation was added), or null if it hasn’t since the rule was created. A change inside the window mixes two splits.

string format: date-time
nullable
evaluable
required

Whether the check could run. See NotEvaluableReason when false.

boolean
pValue

The sample-ratio test’s p-value, or null when not evaluable.

number format: double
nullable
flagged
required

True only when the served split is both unlikely under the configured weights (p < 0.001) and at least 2 percentage points off for some variation.

boolean
notEvaluableReason

Too-little-traffic or unexpected-variation when the check couldn’t run; null otherwise. Allowed values: too-little-traffic, unexpected-variation.

string
nullable
Allowed values: too-little-traffic unexpected-variation
bucketBy
required

The context attribute the rollout hashes on. A context without it skips the rule, even at 100%.

string
unreached

A live rollout rule that no evaluations reached.

object
eligibleEvaluations
required

Evaluations that reached the flag’s rules or fallthrough since SinceUtc, while this rule served none.

integer format: int64
sinceUtc
required

The window start, or the first UTC midnight after the rule last changed when that is later.

string format: date-time

Example

{
"environmentKey": "production",
"days": 7,
"fromUtc": "2026-06-14T00:00:00Z",
"toUtc": "2026-06-20T09:15:00Z",
"totalCount": 10000,
"lastEvaluatedAtUtc": "2026-06-20T09:15:00Z",
"variations": [
{
"variationKey": "true",
"name": "On",
"exists": true,
"count": 4080,
"share": 0.408
},
{
"variationKey": "false",
"name": "Off",
"exists": true,
"count": 5920,
"share": 0.592
}
],
"sources": [
{
"source": "rule",
"ruleId": "0197b6a3-5e6f-7a7b-8c8d-9e0f1a2b3c4d",
"ruleLabel": "Beta users 50/50",
"ruleExists": true,
"count": 8000,
"share": 0.8,
"variations": [
{
"variationKey": "true",
"name": "On",
"exists": true,
"count": 4080,
"share": 0.51
},
{
"variationKey": "false",
"name": "Off",
"exists": true,
"count": 3920,
"share": 0.49
}
],
"rollout": {
"configured": [
{
"variationKey": "true",
"name": "On",
"weight": 50
},
{
"variationKey": "false",
"name": "Off",
"weight": 50
}
],
"evaluable": true,
"pValue": 0.074,
"flagged": false,
"bucketBy": "user_id"
}
},
{
"source": "fallthrough",
"ruleExists": false,
"count": 2000,
"share": 0.2,
"variations": [
{
"variationKey": "false",
"name": "Off",
"exists": true,
"count": 2000,
"share": 1
}
]
}
]
}
X-RateLimit-Limit
integer

The maximum number of requests permitted per rate-limit window for this caller.

X-RateLimit-Remaining
integer

The number of requests remaining in the current rate-limit window.

X-RateLimit-Reset
integer

The UTC time at which the current rate-limit window resets, as a Unix timestamp in seconds.

Bad Request

Media type application/json

The frozen public-API error contract. error codes are stable snake_case strings. Wire keys are frozen snake_case too (error, message, docs_url, fields, retry_after) — the global camelCase naming policy would otherwise emit docsUrl/retryAfter, breaking the published spec. !:JsonPropertyName always wins over the policy, so these are pinned explicitly rather than relying on the property names already being lowercase for the single-word ones. did_you_mean, next_actions and connection_id are ADDITIVE optional keys (null → omitted via the global DefaultIgnoreCondition = WhenWritingNull), so pre-existing error bodies are byte-for-byte unchanged when they’re absent.

connection_id is present only on the sso_required error: the organization requires single sign-on, and this credential didn’t come through its identity provider. connection_id identifies which SSO connection to sign in with. plan_limit is present only on the plan_limit_reached error: which plan cap the request would have exceeded, so a client can branch on it without parsing message.

object
error
required
string
message
required
string
docs_url
required
string
fields
object
key
additional properties
Array<string>
retry_after
integer format: int32
nullable
did_you_mean
Array<string>
nullable
next_actions
Array<object>
nullable
object
method
required
string
path
required
string
connection_id
string format: uuid
nullable
plan_limit

The cap behind a plan_limit_reached error. resource is the capped collection (projects, environments, flags, webhooks, members); plan is the plan’s wire name, as GET /api/v1/orgs/{org} returns it; max is the cap. The environment and flag caps are per project.

object
resource
required
string
plan
required
string
max
required
integer format: int32

Example

{
"error": "not_found",
"message": "Flag 'new-checkout-flw' was not found in project 'checkout'.",
"docs_url": "https://featureflip.io/docs/management-api/errors/not_found",
"did_you_mean": [
"new-checkout-flow"
],
"next_actions": [
{
"method": "GET",
"path": "/api/v1/orgs/acme/projects/checkout/flags"
}
]
}
X-RateLimit-Limit
integer

The maximum number of requests permitted per rate-limit window for this caller.

X-RateLimit-Remaining
integer

The number of requests remaining in the current rate-limit window.

X-RateLimit-Reset
integer

The UTC time at which the current rate-limit window resets, as a Unix timestamp in seconds.

Authentication is required, or the supplied API token is invalid or expired.

Media type application/json

The frozen public-API error contract. error codes are stable snake_case strings. Wire keys are frozen snake_case too (error, message, docs_url, fields, retry_after) — the global camelCase naming policy would otherwise emit docsUrl/retryAfter, breaking the published spec. !:JsonPropertyName always wins over the policy, so these are pinned explicitly rather than relying on the property names already being lowercase for the single-word ones. did_you_mean, next_actions and connection_id are ADDITIVE optional keys (null → omitted via the global DefaultIgnoreCondition = WhenWritingNull), so pre-existing error bodies are byte-for-byte unchanged when they’re absent.

connection_id is present only on the sso_required error: the organization requires single sign-on, and this credential didn’t come through its identity provider. connection_id identifies which SSO connection to sign in with. plan_limit is present only on the plan_limit_reached error: which plan cap the request would have exceeded, so a client can branch on it without parsing message.

object
error
required
string
message
required
string
docs_url
required
string
fields
object
key
additional properties
Array<string>
retry_after
integer format: int32
nullable
did_you_mean
Array<string>
nullable
next_actions
Array<object>
nullable
object
method
required
string
path
required
string
connection_id
string format: uuid
nullable
plan_limit

The cap behind a plan_limit_reached error. resource is the capped collection (projects, environments, flags, webhooks, members); plan is the plan’s wire name, as GET /api/v1/orgs/{org} returns it; max is the cap. The environment and flag caps are per project.

object
resource
required
string
plan
required
string
max
required
integer format: int32

Example

{
"error": "not_found",
"message": "Flag 'new-checkout-flw' was not found in project 'checkout'.",
"docs_url": "https://featureflip.io/docs/management-api/errors/not_found",
"did_you_mean": [
"new-checkout-flow"
],
"next_actions": [
{
"method": "GET",
"path": "/api/v1/orgs/acme/projects/checkout/flags"
}
]
}
X-RateLimit-Limit
integer

The maximum number of requests permitted per rate-limit window for this caller.

X-RateLimit-Remaining
integer

The number of requests remaining in the current rate-limit window.

X-RateLimit-Reset
integer

The UTC time at which the current rate-limit window resets, as a Unix timestamp in seconds.

Not Found

Media type application/json

The frozen public-API error contract. error codes are stable snake_case strings. Wire keys are frozen snake_case too (error, message, docs_url, fields, retry_after) — the global camelCase naming policy would otherwise emit docsUrl/retryAfter, breaking the published spec. !:JsonPropertyName always wins over the policy, so these are pinned explicitly rather than relying on the property names already being lowercase for the single-word ones. did_you_mean, next_actions and connection_id are ADDITIVE optional keys (null → omitted via the global DefaultIgnoreCondition = WhenWritingNull), so pre-existing error bodies are byte-for-byte unchanged when they’re absent.

connection_id is present only on the sso_required error: the organization requires single sign-on, and this credential didn’t come through its identity provider. connection_id identifies which SSO connection to sign in with. plan_limit is present only on the plan_limit_reached error: which plan cap the request would have exceeded, so a client can branch on it without parsing message.

object
error
required
string
message
required
string
docs_url
required
string
fields
object
key
additional properties
Array<string>
retry_after
integer format: int32
nullable
did_you_mean
Array<string>
nullable
next_actions
Array<object>
nullable
object
method
required
string
path
required
string
connection_id
string format: uuid
nullable
plan_limit

The cap behind a plan_limit_reached error. resource is the capped collection (projects, environments, flags, webhooks, members); plan is the plan’s wire name, as GET /api/v1/orgs/{org} returns it; max is the cap. The environment and flag caps are per project.

object
resource
required
string
plan
required
string
max
required
integer format: int32

Example

{
"error": "not_found",
"message": "Flag 'new-checkout-flw' was not found in project 'checkout'.",
"docs_url": "https://featureflip.io/docs/management-api/errors/not_found",
"did_you_mean": [
"new-checkout-flow"
],
"next_actions": [
{
"method": "GET",
"path": "/api/v1/orgs/acme/projects/checkout/flags"
}
]
}
X-RateLimit-Limit
integer

The maximum number of requests permitted per rate-limit window for this caller.

X-RateLimit-Remaining
integer

The number of requests remaining in the current rate-limit window.

X-RateLimit-Reset
integer

The UTC time at which the current rate-limit window resets, as a Unix timestamp in seconds.

Rate limit exceeded. Retry after the interval indicated by the Retry-After header.

Media type application/json

The frozen public-API error contract. error codes are stable snake_case strings. Wire keys are frozen snake_case too (error, message, docs_url, fields, retry_after) — the global camelCase naming policy would otherwise emit docsUrl/retryAfter, breaking the published spec. !:JsonPropertyName always wins over the policy, so these are pinned explicitly rather than relying on the property names already being lowercase for the single-word ones. did_you_mean, next_actions and connection_id are ADDITIVE optional keys (null → omitted via the global DefaultIgnoreCondition = WhenWritingNull), so pre-existing error bodies are byte-for-byte unchanged when they’re absent.

connection_id is present only on the sso_required error: the organization requires single sign-on, and this credential didn’t come through its identity provider. connection_id identifies which SSO connection to sign in with. plan_limit is present only on the plan_limit_reached error: which plan cap the request would have exceeded, so a client can branch on it without parsing message.

object
error
required
string
message
required
string
docs_url
required
string
fields
object
key
additional properties
Array<string>
retry_after
integer format: int32
nullable
did_you_mean
Array<string>
nullable
next_actions
Array<object>
nullable
object
method
required
string
path
required
string
connection_id
string format: uuid
nullable
plan_limit

The cap behind a plan_limit_reached error. resource is the capped collection (projects, environments, flags, webhooks, members); plan is the plan’s wire name, as GET /api/v1/orgs/{org} returns it; max is the cap. The environment and flag caps are per project.

object
resource
required
string
plan
required
string
max
required
integer format: int32

Example

{
"error": "not_found",
"message": "Flag 'new-checkout-flw' was not found in project 'checkout'.",
"docs_url": "https://featureflip.io/docs/management-api/errors/not_found",
"did_you_mean": [
"new-checkout-flow"
],
"next_actions": [
{
"method": "GET",
"path": "/api/v1/orgs/acme/projects/checkout/flags"
}
]
}
Retry-After
integer

Number of seconds to wait before retrying the request.

X-RateLimit-Limit
integer

The maximum number of requests permitted per rate-limit window for this caller.

X-RateLimit-Remaining
integer

The number of requests remaining in the current rate-limit window.

X-RateLimit-Reset
integer

The UTC time at which the current rate-limit window resets, as a Unix timestamp in seconds.