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

# Manage Flags

> Create, update, toggle, and audit feature flags and environments with an API key

`/api/v1/org/flags` and `/api/v1/org/flag-environments` are the management surface behind the dashboard and the `grantiva` CLI. The SDK-facing [`GET /api/v1/flags`](/api-reference/flags/get-flags) only reads resolved values; everything here writes configuration.

## Authentication

| Operation | Key scope     | Session role |
| --------- | ------------- | ------------ |
| Read      | `flags:read`  | viewer+      |
| Write     | `flags:write` | member+      |

Send an API key as `Authorization: Bearer gpat_…`/`aat_…`, or use a dashboard session. Wire format is snake\_case.

`:flagRef` accepts either the flag's UUID or its `flag_key`.

***

## The flag object

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "flag_key": "dark_mode",
  "name": "Dark Mode",
  "description": "Enables the dark colour scheme",
  "app_id": null,
  "value_type": "boolean",
  "is_active": true,
  "environment_values": {
    "production": { "on_value": "true", "off_value": "false", "is_active": true },
    "staging": { "on_value": "true", "off_value": "false", "is_active": false }
  },
  "rule_count": 2,
  "created_at": "2026-01-15T12:00:00Z",
  "updated_at": "2026-07-01T08:30:00Z"
}
```

| Field                | Description                                                                                                       |
| -------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `app_id`             | The app this flag is scoped to, or `null` for an organization-wide flag                                           |
| `value_type`         | `boolean`, `integer`, `double`, `string`, or `json`                                                               |
| `is_active`          | The global kill switch. Turning it off also deactivates the flag in every environment                             |
| `environment_values` | Keyed by environment slug. `is_active` per environment decides whether the SDK receives `on_value` or `off_value` |
| `rule_count`         | Number of active targeting rules                                                                                  |

***

## List flags

```
GET /api/v1/org/flags
```

Returns an array of flag objects sorted by `flag_key`.

| Parameter     | Type   | Description                                                               |
| ------------- | ------ | ------------------------------------------------------------------------- |
| `app_id`      | UUID   | Only flags scoped to this app. A non-UUID returns `400`                   |
| `environment` | string | Restrict `environment_values` to this slug. An unknown slug returns `404` |

***

## Create a flag

```
POST /api/v1/org/flags
```

```json theme={null}
{
  "flag_key": "dark_mode",
  "name": "Dark Mode",
  "description": "Enables the dark colour scheme",
  "app_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "value_type": "boolean",
  "is_active": true,
  "environment_values": {
    "production": { "on_value": "true", "off_value": "false", "is_active": false }
  }
}
```

| Field                | Type        | Required | Description                                                                                 |
| -------------------- | ----------- | -------- | ------------------------------------------------------------------------------------------- |
| `flag_key`           | string      | Yes      | Lowercase letters, digits, and underscores, starting with a letter. Unique per organization |
| `name`               | string      | Yes      | Display name                                                                                |
| `value_type`         | string      | Yes      | `boolean`, `integer`, `double`, `string`, or `json`                                         |
| `description`        | string      | No       | Free-form description                                                                       |
| `app_id`             | UUID string | No       | Scope the flag to one app. Must belong to your organization                                 |
| `is_active`          | boolean     | No       | Global kill switch                                                                          |
| `environment_values` | object      | No       | Per-slug values. Slugs must exist. Environments you omit get type-appropriate defaults      |

The flag row, its per-environment values, and this payload commit together — a rejected request leaves nothing behind.

**Response** — the created flag object.

***

## Get a flag

```
GET /api/v1/org/flags/:flagRef
```

Returns the flag with its rules and overrides inlined:

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "flag_key": "dark_mode",
  "name": "Dark Mode",
  "description": null,
  "app_id": null,
  "value_type": "boolean",
  "is_active": true,
  "environment_values": {
    "production": { "on_value": "true", "off_value": "false", "is_active": true }
  },
  "rules": [
    {
      "id": "6f9619ff-8b86-d011-b42d-00cf4fc964ff",
      "name": "Beta testers on iOS 18+",
      "priority": 0,
      "value": "true",
      "rollout_percentage": 50,
      "is_active": true
    }
  ],
  "overrides": [
    {
      "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "flag_id": "550e8400-e29b-41d4-a716-446655440000",
      "device_key_id": "abc123",
      "forced_value": "true",
      "expires_at": "2026-04-01T00:00:00Z",
      "created_at": "2026-03-01T12:00:00Z",
      "created_by": "qa@example.com"
    }
  ],
  "created_at": "2026-01-15T12:00:00Z",
  "updated_at": "2026-07-01T08:30:00Z"
}
```

Rules are sorted by priority; overrides newest first.

***

## Update a flag

```
PUT /api/v1/org/flags/:flagRef
```

Partial update — only the fields you send change. `flag_key` and `value_type` are immutable.

```json theme={null}
{
  "name": "Dark Mode (v2)",
  "is_active": false,
  "environment_values": {
    "staging": { "is_active": true }
  }
}
```

`is_active` is applied first and propagates to every environment; the `environment_values` you name are then applied on top, so a per-environment `is_active` wins for exactly those environments.

**Response** — the updated flag object.

***

## Toggle a flag

```
POST /api/v1/org/flags/:flagRef/toggle
```

```json theme={null}
{ "is_active": true, "environment": "staging" }
```

| Field         | Type    | Description                                                                     |
| ------------- | ------- | ------------------------------------------------------------------------------- |
| `is_active`   | boolean | The state to set. Omit it (or send an empty body) to flip the current state     |
| `environment` | string  | Toggle only this environment. Omit to toggle globally, across every environment |

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "flag_key": "dark_mode",
  "is_active": true,
  "environment": "staging"
}
```

A body that is present but doesn't decode returns `400` rather than being treated as a flip.

***

## Delete a flag

```
DELETE /api/v1/org/flags/:flagRef
```

```json theme={null}
{ "deleted": true, "id": "550e8400-e29b-41d4-a716-446655440000" }
```

***

## Change history

```
GET /api/v1/org/flags/:flagRef/history
```

| Parameter | Type | Default | Description     |
| --------- | ---- | ------- | --------------- |
| `limit`   | int  | 20      | 1–100           |
| `offset`  | int  | 0       | Entries to skip |

```json theme={null}
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "flag_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "actor_email": "dev@example.com",
    "change_type": "flag.updated",
    "summary": "Updated flag settings",
    "created_at": "2026-07-01T08:30:00Z"
  }
]
```

`change_type` is the audit action — `flag.created`, `flag.updated`, `flag.toggled`, `flag.deleted`, `flag.rule_created`, `flag.rule_updated`, `flag.rule_deleted`, `flag.override_created`, or `flag.override_deleted` — and `summary` is its human-readable form.

***

## Recent evaluations

```
GET /api/v1/org/flags/:flagRef/evaluations
```

| Parameter | Type | Default | Description |
| --------- | ---- | ------- | ----------- |
| `limit`   | int  | 50      | 1–200       |

```json theme={null}
{
  "evaluations": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "device_key_id": "abc123",
      "value": "true",
      "evaluated_at": "2026-07-26T11:59:31Z"
    }
  ]
}
```

Newest first. `device_key_id` is `null` when the device sent no `X-Device-ID`.

***

## Overrides

```
GET    /api/v1/org/flags/:flagRef/overrides
POST   /api/v1/org/flags/:flagRef/overrides
DELETE /api/v1/org/flags/:flagRef/overrides/:overrideId
```

```json theme={null}
{
  "device_key_id": "abc123",
  "forced_value": "true",
  "expires_at": "2026-04-01T00:00:00Z"
}
```

Same rules as the dashboard surface — see [Flag Overrides](/api-reference/flags/overrides) for semantics and validation. Delete returns `204 No Content`.

***

## Environments

```
GET    /api/v1/org/flag-environments
POST   /api/v1/org/flag-environments
PUT    /api/v1/org/flag-environments/:envId
DELETE /api/v1/org/flag-environments/:envId
```

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Production",
  "slug": "production",
  "color": "#6b7280",
  "is_default": true,
  "sort_order": 0,
  "created_at": "2026-01-15T12:00:00Z"
}
```

**Create** takes `{ "name": "QA", "slug": "qa", "color": "#22c55e" }`. `slug` defaults to a slugified `name`; `color` defaults to `#6b7280`.

**Update** is partial and accepts `name`, `color`, `sort_order`, and `reorder` (`"up"` or `"down"` to move the environment in the list).

**Delete** returns `{ "deleted": true, "id": "…" }` and refuses (`403`) on the default environment.

***

## Errors

| Status | Meaning                                                                                                                                 |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| 400    | Invalid `flag_key` format, unknown `value_type`, `app_id` that is not a UUID or not one of your apps, or an invalid `reorder` direction |
| 401    | No session and no API key                                                                                                               |
| 403    | Key lacks the required scope, session role too low, feature-flag or environment tier limit reached, or deleting the default environment |
| 404    | No such flag, override, or environment — including an `environment_values` slug that doesn't exist                                      |
| 409    | A flag with that `flag_key`, or an environment with that slug, already exists                                                           |

## See also

* [Get Flags](/api-reference/flags/get-flags) — the SDK read path
* [Flag Targeting Rules](/api-reference/flags/rules)
* [Test an Evaluation](/api-reference/flags/evaluate)
