> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.clubedge.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Evaluation API

> Direct HTTP endpoints for flag evaluation: single, batch, and config fetch with ETag polling. Auth via Bearer SDK key.

The Evaluation API is the server-side surface that SDKs and direct HTTP callers use to resolve flags at runtime. It is authenticated with an environment-scoped SDK key sent in the `Authorization: Bearer` header.

## Authentication

All evaluation endpoints require an SDK key issued for the target environment. Send it in the `Authorization` header:

```http theme={null}
Authorization: Bearer ffk_1a2b3c4d5e6f...
```

The server hashes the key with SHA-256 and looks up the environment. The plaintext key is never stored — only the hash is persisted. If the environment is revoked or the key doesn't match, you get `401 Unauthorized`.

<Note>
  Some endpoints also accept `sdkKey` in the request body for backward compatibility with older clients. When both are present, the `Authorization` header takes precedence. New integrations should rely on the header only.
</Note>

## Endpoints

### Evaluate a single flag

Resolves one flag for a given context.

```http theme={null}
POST /sdk/v1/evaluate
Authorization: Bearer ffk_1a2b3c4d5e6f
Content-Type: application/json

{
  "flagKey": "new_dashboard",
  "context": {
    "userId": "user-123",
    "tenantId": "tenant-456",
    "email": "user@example.com",
    "country": "US",
    "customAttributes": {
      "plan": "premium",
      "signupDate": "2025-01-15"
    }
  }
}
```

**Response `200 OK`:**

```json theme={null}
{
  "enabled": true,
  "reason": "targeting_rule"
}
```

| Field     | Type      | Description                                                     |
| --------- | --------- | --------------------------------------------------------------- |
| `enabled` | `boolean` | Whether the flag is on for this context                         |
| `reason`  | `string`  | Why this result — see [Evaluation reasons](#evaluation-reasons) |

### Evaluate multiple flags (batch)

Evaluate up to 100 flags in a single request. Results are returned in the same order as the `evaluations` array.

```http theme={null}
POST /sdk/v1/evaluate/batch
Authorization: Bearer ffk_1a2b3c4d5e6f
Content-Type: application/json

{
  "evaluations": [
    { "flagKey": "new_dashboard", "context": { "userId": "user-123" } },
    { "flagKey": "welcome_message", "context": { "userId": "user-123" } }
  ]
}
```

**Response `200 OK`:**

```json theme={null}
[
  { "enabled": true, "reason": "flag_enabled" },
  { "enabled": false, "reason": "flag_disabled" }
]
```

A single unknown flag key in a batch does not fail the whole request — that entry returns `{ "enabled": false, "reason": "flag_disabled" }` while the rest evaluate normally.

<Note>
  Maximum 100 evaluations per request. The `evaluations` array must contain at least one item.
</Note>

### Fetch flag configurations

Fetches full flag configurations (rules, rollout, enabled state) for caching. This is what the official SDKs call internally during `initialize()` and on each poll cycle.

```http theme={null}
GET /sdk/v1/config?keys[]=new_dashboard&keys[]=checkout_experiment
Authorization: Bearer ffk_1a2b3c4d5e6f
```

If `keys[]` is omitted, all active flags for the environment are returned.

**Response `200 OK`:**

```json theme={null}
{
  "flags": [
    {
      "key": "new_dashboard",
      "enabled": true,
      "rules": [
        {
          "priority": 1,
          "logic": "and",
          "value": true,
          "conditions": [
            {
              "attribute": "country",
              "operator": "==",
              "valueType": "string",
              "valueString": "TN"
            }
          ]
        }
      ],
      "rollout": null
    }
  ]
}
```

**ETag support:** The endpoint returns an `ETag` header. Send it back with `If-None-Match` on subsequent polls to avoid re-downloading unchanged configs:

```http theme={null}
GET /sdk/v1/config?keys[]=new_dashboard
Authorization: Bearer ffk_1a2b3c4d5e6f
If-None-Match: "abc123tag"
```

If nothing changed, the server returns `304 Not Modified` with no body. Always store and send the returned `ETag`.

## Evaluation reasons

| Reason           | Description                                                         |
| ---------------- | ------------------------------------------------------------------- |
| `flag_enabled`   | Flag is enabled in the environment with no matching rule or rollout |
| `flag_disabled`  | Flag is disabled in the environment                                 |
| `flag_archived`  | Flag has been archived                                              |
| `targeting_rule` | A targeting rule matched the context                                |
| `rollout`        | A percentage rollout bucketed the user in (or out)                  |

## Context attributes

Pass as much context as available for targeting rules and percentage rollouts:

| Attribute          | Type                                          | Used for                               |
| ------------------ | --------------------------------------------- | -------------------------------------- |
| `userId`           | `string`                                      | Targeting, `per_user` rollout          |
| `tenantId`         | `string`                                      | Targeting, `per_tenant` rollout        |
| `email`            | `string`                                      | Targeting (must be valid email format) |
| `country`          | `string`                                      | Targeting                              |
| `customAttributes` | `Record<string, string \| number \| boolean>` | Arbitrary targeting                    |

## Error reference

<Table>
  <TableHeader>
    <Row><Header>Status</Header><Header>Meaning</Header><Header>Typical fix</Header></Row>
  </TableHeader>

  <TableBody>
    <Row><Cell>200</Cell><Cell>Success</Cell><Cell>—</Cell></Row>
    <Row><Cell>304</Cell><Cell>Not Modified (ETag match)</Cell><Cell>Store new ETag for next poll</Cell></Row>
    <Row><Cell>400</Cell><Cell>Malformed request body or invalid parameters</Cell><Cell>Validate JSON structure and field types</Cell></Row>
    <Row><Cell>401</Cell><Cell>Missing, invalid, or revoked SDK key</Cell><Cell>Verify key matches the environment; rotate if revoked</Cell></Row>
    <Row><Cell>404</Cell><Cell>Flag not found or not configured for environment</Cell><Cell>Check flag key exists and is enabled for the environment</Cell></Row>
    <Row><Cell>429</Cell><Cell>Too many requests</Cell><Cell>Official SDKs handle this with backoff; implement your own for direct HTTP</Cell></Row>
    <Row><Cell>500</Cell><Cell>Unexpected server error</Cell><Cell>Safe to retry with backoff</Cell></Row>
  </TableBody>
</Table>
