---
title: "Set a feature flag's global default (platform admin)"
method: PUT
path: "/v1/admin/feature-flags/{key}"
tags: ["Internal"]
---

# Set a feature flag's global default (platform admin)

`PUT /v1/admin/feature-flags/{key}`

Upserts the flag's #DEFAULT row on the config table, the fast no-deploy on/off toggle layered over the registry's compile-time default. Rejected with 400 for a key the registry does not know. The durable default stays the Go registry constant (a cold or errored resolver falls back to it); this row only flips the live value on top of it. reason is recorded in the admin audit log.

## Path parameters

- `key` string, required

## Request body

- SetFeatureFlagRequest — Set the flag's global #DEFAULT row (the fast on/off toggle over the registry default).
  - `enabled` boolean, required
  - `reason` string, required — Why the change is made; recorded in the admin audit log, never on the row

## Response `200`

Applied

- FeatureFlag — One feature flag as the admin surface sees it: the compile-time registry entry (services/store/flags) unioned with the stored rows on the config table's FLAGS partition. codeDefault is the durable registry value a cold or errored resolver falls back to; storedDefault (when present) is the fast, no-deploy #DEFAULT row layered over it; overrides are the per-subject allow/deny rows. orphaned marks a stored key with no registry entry (a retired or misspelled flag) so it can be cleaned up rather than vanish.
  - `codeDefault` boolean, required — Registry Default: the outage/cold floor. false for an orphaned key (its zero value).
  - `dashboard` boolean, required — Surfaced to the customer dashboard (the /v1/me flags map)
  - `description` string — Operator-facing copy from the registry; empty for an orphaned key
  - `effectiveDefault` boolean, required — storedDefault when set, else codeDefault: what a subject with no override resolves to
  - `key` string, required — Stable flag key (uppercase-with-underscores)
  - `orphaned` boolean, required — Stored rows exist for a key the registry does not know; it resolves to false at runtime and is cleaned up out of band, never toggled here
  - `overrides` FeatureFlagSubjectOverride[], required — Per-subject allow/deny rows (empty for a global-scope flag)
    - `enabled` boolean, required — true = allow this subject, false = deny it (distinct from having no override row)
    - `subjectId` string, required — The org id or node id
    - `subjectType` 'org' | 'node', required — Which subject space the id lives in (maps to the ORG#/NODE# SK prefix)
    - `updatedAt` string
    - `updatedBy` string
  - `scope` 'global' | 'org' | 'node', required — Which override rows the flag may carry: a global flag has only a default, an org/node flag also takes per-subject overrides. For an orphaned key this is inferred from the subject types of its stored rows.
  - `storedDefault` boolean — The stored #DEFAULT row's value, when one exists; omitted when only the code default applies
  - `storedDefaultUpdatedAt` string — When the #DEFAULT row was last written (RFC3339)
  - `storedDefaultUpdatedBy` string — Who last wrote the #DEFAULT row

## Other responses

- `400` — The request is invalid
- `401` — Missing or invalid API key
- `403` — API key lacks the required scope
- `503` — A required integration (e.g. payments) is not configured

## Changes

- **2026-09-04** `4a338e447d39` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/openrelay/apis/openrelay-api/changes/v1/admin/feature-flags/:key/put.md)

---

[API](https://skmtc.dev/openrelay/apis/openrelay-api.md) · [All operations](https://skmtc.dev/openrelay/apis/openrelay-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/openrelay/openrelay-api/revisions/4a338e447d39/schema)
