Records analytics events from a client SDK.
const url = 'https://eval.featureflip.io/v1/client/events';const options = { method: 'POST', headers: {Authorization: '<Authorization>', 'Content-Type': 'application/json'}, body: '{"events":[{"type":"Evaluation","flagKey":"example","userId":"example","variation":"example","timestamp":"2026-04-15T12:00:00Z","metadata":{"additionalProperty":"example"},"prerequisiteKey":"example","reason":"example","ruleId":"example"}]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://eval.featureflip.io/v1/client/events \ --header 'Authorization: <Authorization>' \ --header 'Content-Type: application/json' \ --data '{ "events": [ { "type": "Evaluation", "flagKey": "example", "userId": "example", "variation": "example", "timestamp": "2026-04-15T12:00:00Z", "metadata": { "additionalProperty": "example" }, "prerequisiteKey": "example", "reason": "example", "ruleId": "example" } ] }'The client-surface counterpart of POST /v1/sdk/events, for SDKs that authenticate
with a client key. The mobile SDKs (Swift, Android, Flutter) use this to report
track() calls. Server SDKs keep using /v1/sdk/events.
A client that sends X-Featureflip-Reports-Evaluations: 1 on evaluate and
identify reports the flags its code actually reads here, as Evaluation events
(one per flag, variation and user is enough). For clients that don’t send the header, this
API records the evaluations it serves on their behalf.
Because a client key is public by design, this endpoint is rate limited per client IP, limits the size of a request, and caps the number of events in one request. An event that exceeds one of the following per-event limits is discarded on its own; the rest of the batch is still recorded, and the response is unchanged:
- its
timestampsits far outside the present; - its
flagKeyis longer than 256 characters; - it is a
Customevent introducing more than 50 distinct event keys in one request. Repeats of a key already in the request are always recorded, so this bounds how many distinct event names a single batch can introduce, not how many events it may carry.
Authorizations
Section titled “ Authorizations ”Request Body
Section titled “ Request Body ”Batch of events to record.
object
object
object
Optional. Why the evaluation served its variation: rule-match, fallthrough,
flag-disabled, prerequisite-failed, error or flag-not-found.
Used to attribute evaluation traffic in flag analytics; events without it count as an
unknown source.
Optional. The id of the targeting rule that matched, when reason is
rule-match.
object
object
object
Optional. Why the evaluation served its variation: rule-match, fallthrough,
flag-disabled, prerequisite-failed, error or flag-not-found.
Used to attribute evaluation traffic in flag analytics; events without it count as an
unknown source.
Optional. The id of the targeting rule that matched, when reason is
rule-match.
object
object
object
Optional. Why the evaluation served its variation: rule-match, fallthrough,
flag-disabled, prerequisite-failed, error or flag-not-found.
Used to attribute evaluation traffic in flag analytics; events without it count as an
unknown source.
Optional. The id of the targeting rule that matched, when reason is
rule-match.
Responses
Section titled “ Responses ”Events were accepted for processing.
The batch exceeds the maximum number of events per request.
object
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Client SDK key is missing or invalid.
object
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}The request body is larger than this endpoint accepts.
object
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}