Gets evaluation counts for the flag in one environment.
const url = 'https://api.featureflip.io/api/v1/orgs/example/projects/example/flags/example/environments/example/evaluations?days=7';const options = {method: 'GET', headers: {Authorization: '<Authorization>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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).
Authorizations
Section titled “ Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “ Path Parameters ”Query Parameters
Section titled “ Query Parameters ”Responses
Section titled “ Responses ”OK
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
The environment’s key.
The window requested: 7, 30 or 90.
Start of the window: UTC midnight days - 1 days ago, or the flag’s creation day if later.
When the counts were read.
Evaluations in the window. Evaluation counts, not unique users.
The last reported evaluation, or null if none was reported.
Evaluations per variation over the window.
One variation’s evaluations.
object
The variation served, or null for evaluations recorded without one.
The variation’s name, or null when the key no longer matches one of the flag’s variations.
False when the key no longer matches one of the flag’s variations.
Evaluations that served this variation.
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.
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.
The evaluations one part of the targeting served.
object
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.
For a rule, its id (rules have no key). Null otherwise, or when the SDK didn’t say which rule.
For a live rule, its description or a generated label. Null otherwise.
False when the rule is no longer in the environment’s targeting.
Evaluations this source served.
Count as a fraction (0 to 1) of all sources’ counts combined.
What this source served, with shares of this source’s count.
One variation’s evaluations.
object
The variation served, or null for evaluations recorded without one.
The variation’s name, or null when the key no longer matches one of the flag’s variations.
False when the key no longer matches one of the flag’s variations.
Evaluations that served this variation.
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.
A percentage-rollout rule’s configured split beside a sample-ratio check of what it served.
object
The configured weights, in percent; they sum to 100.
A variation’s configured share of a rollout rule.
object
The variation’s key.
The variation’s name, or null when the key no longer matches one of the flag’s variations.
Percent of the rule’s traffic.
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.
Whether the check could run. See NotEvaluableReason when false.
The sample-ratio test’s p-value, or null when not evaluable.
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.
Too-little-traffic or unexpected-variation when the check couldn’t run; null otherwise. Allowed values: too-little-traffic, unexpected-variation.
The context attribute the rollout hashes on. A context without it skips the rule, even at 100%.
A live rollout rule that no evaluations reached.
object
Evaluations that reached the flag’s rules or fallthrough since SinceUtc, while this rule served none.
The window start, or the first UTC midnight after the rule last changed when that is later.
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 } ] } ]}Headers
Section titled “ Headers ”The maximum number of requests permitted per rate-limit window for this caller.
The number of requests remaining in the current rate-limit window.
The UTC time at which the current rate-limit window resets, as a Unix timestamp in seconds.
Bad Request
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
object
object
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
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" } ]}Headers
Section titled “ Headers ”The maximum number of requests permitted per rate-limit window for this caller.
The number of requests remaining in the current rate-limit window.
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.
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
object
object
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
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" } ]}Headers
Section titled “ Headers ”The maximum number of requests permitted per rate-limit window for this caller.
The number of requests remaining in the current rate-limit window.
The UTC time at which the current rate-limit window resets, as a Unix timestamp in seconds.
Not Found
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
object
object
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
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" } ]}Headers
Section titled “ Headers ”The maximum number of requests permitted per rate-limit window for this caller.
The number of requests remaining in the current rate-limit window.
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.
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
object
object
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
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" } ]}Headers
Section titled “ Headers ”Number of seconds to wait before retrying the request.
The maximum number of requests permitted per rate-limit window for this caller.
The number of requests remaining in the current rate-limit window.
The UTC time at which the current rate-limit window resets, as a Unix timestamp in seconds.