Idempotency.POST writes that create resources accept Idempotency-Key: <uuid> and replay
the same response if you retry within 24h.
Gates
GET/api/admin/gates
List feature gates
Returns a single page of gates ordered by updated_at desc, id desc. Use the cursor query parameter to paginate.
Use caseSnapshot every gate in the project — for example to render an admin overview or to drive a CI check that asserts no gate is left at 100% in staging.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
limit
query
number
Max results per page (default 50, max 500).
cursor
query
string
Opaque pagination cursor from a prior page's `next_cursor`.
Creates a new gate. Default enabled: true at the supplied rollout_pct (0 = fully dark).
Only name is required. Request fields use snake_case (owner_email); the GET response returns camelCase (ownerEmail, groupName).
Returns 409 if name already exists in the project (case-sensitive).
Use cases
Use case
Description
Example
Dark create + ramp later
{ "name": "checkout_v2" } at 0% rollout. Ramp via PATCH after deploy validation.
Targeted rollout
supply rules to gate the caller (e.g. only plan = pro users) plus a rollout_pct to bucket within that audience.
Gatekeeper stack
supply stack instead of rules/rollout_pct for internal ∪ beta ∪ public fall-through. Stack entries evaluated top-to-bottom; first match wins.
Dashboard metadata
populate title, description, folder, group, owner_email so the admin UI is self-documenting from day one.
—
Disabled on create
pre-provision with enabled: false for a future launch; flip on with POST /{id}/enable at go-live.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
Body
Name
Type
Description
namerequired
string
Stable gate key used by SDKs (`Shipeasy.checkGate(user, '<name>')`). Lowercase letters, digits, `_` or `-`, must start with a letter/digit, max 64 chars. Immutable after create — rename = delete + recreate.
enabled
boolean
Master switch. Defaults to `true`. Set `false` to create the gate disabled (evaluates to `false` regardless of rules/rollout); flip on via `POST /{id}/enable` or PATCH. default: true
rollout_pct
integer
Initial rollout in basis points (0–10000 = 0%–100%). Use `0` to create the gate dark and ramp via PATCH after deploy validation. default: 0
Targeting predicates. AND-combined. If non-empty, the gate returns `true` only for callers that satisfy every rule **and** fall under `rollout_pct`. default: []
salt
string
Hash salt for percentage bucketing. Auto-generated if omitted. Provide explicitly to keep a gate's buckets stable across delete/recreate. **Immutable after create** — there is no PATCH for `salt` because changing it would re-bucket every caller.
Optional gatekeeper stack. When provided, takes precedence over `rules` + `rollout_pct` at evaluation time. Omit (or pass `null`) for a flat gate.
title
string
Human-readable title shown in the dashboard. Free-form, no key format constraint.
description
string
Long-form description / runbook. Markdown is rendered in the dashboard.
folder
string
Folder label for dashboard organisation. Free-form; folders are inferred from the set of values.
group
string
Group label for dashboard organisation (e.g. team or product area).
owner_email
string
Owner contact. Displayed verbatim; not used for auth.
Response · 201
Name
Type
Description
idrequired
string
Newly assigned gate id (`gat_…`).
namerequired
string
Stable gate key used by SDKs (`Shipeasy.checkGate(user, '<name>')`). Lowercase letters, digits, `_` or `-`, must start with a letter/digit, max 64 chars. Immutable after create — rename = delete + recreate.
{ "enabled": false }. Forces evaluation to false for every caller regardless of rules/rollout. Re-enable with POST /{id}/enable or { "enabled": true }.
Modify a rule's `in` set
send the full new rules array. To add 'GB' to ['US','CA']: { "rules": [{ "attr": "country", "op": "in", "value": ["US","CA","GB"] }] }. No per-rule patch endpoint.
Replaces the rule list wholesale. To add a value to an `in` rule, send the full new `rules` array with the augmented `value` (e.g. previous `['US','CA']` → `['US','CA','GB']`).
enabled
boolean
Master switch. `false` makes the gate evaluate to `false` for every caller regardless of `rollout_pct`, `rules`, or `stack` — use as kill switch.
Returns a single page of non-archived experiments ordered by updated_at desc, id desc. Use the cursor query parameter to paginate.
Use caseSnapshot every active experiment in the project — e.g. render an overview dashboard or drive a CI check that no experiment has been running past its min_runtime_days.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
limit
query
number
Max results per page (default 50, max 500).
cursor
query
string
Opaque pagination cursor from a prior page's `next_cursor`.
Creates a new experiment in draft status. name, universe, and groups are required; everything else has sensible defaults.
Returns 409 if name already exists, 422 if the named universe doesn't exist, 403 if a plan-gated option is set (sequential_testing, custom significance_threshold) on a plan that doesn't include it.
Use cases
Use case
Description
Example
Minimal 50/50
name + universe + two equal-weight groups.
Targeted rollout
supply targeting_gate to restrict the eligible audience and allocation_pct to enrol a slice of it.
Multivariant
three or more groups with weights summing to 10000.
Sequential testing
sequential_testing: true for Premium plans.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
Body
Name
Type
Description
namerequired
string
Stable experiment key (a-z, 0-9, `_`/`-`, must start with letter/digit, max 64 chars). Used by SDKs as `Shipeasy.getExperiment(user, '<name>')`. Immutable after create.
description
string | null
Free-form description. Max 2000 chars, markdown rendered in the dashboard. default: null
tag
string | null
Optional tag used to group experiments in the dashboard. default: null
universerequired
string
Name of an existing universe in the project. Returns `422` if the universe doesn't exist.
targeting_gate
string | null
Optional gate name. Only callers that pass the gate are enrolled in the experiment. default: null
allocation_pct
integer
Share of the (gated) audience allocated to the experiment, in basis points (0–10000 = 0%–100%). `0` = unallocated. Immutable while the experiment is running. default: 0
salt
string
Hash salt for bucketing. Auto-generated if omitted. Immutable while running.
params
object
Map of param-name → scalar type. Defines the shape of `groups[].params`. Example: `{ headline: 'string', show_cta: 'bool' }`. default: {}
Two or more variants. Weights must sum to exactly 10000 (100%). Immutable while running.
significance_threshold
number
p-value cutoff used by the analysis pass. Defaults to `0.05`. Values other than 0.05 require Pro plan or higher. default: 0.05
min_runtime_days
integer
Minimum days the experiment must run before results are considered conclusive. default: 0
min_sample_size
integer
Minimum exposures per group before results are considered conclusive. default: 100
sequential_testing
boolean
Enable sequential testing (always-valid p-values). Requires Premium plan or higher. default: false
Response · 201
Name
Type
Description
idrequired
string
Newly assigned experiment id.
namerequired
string
Stable experiment key (a-z, 0-9, `_`/`-`, must start with letter/digit, max 64 chars). Used by SDKs as `Shipeasy.getExperiment(user, '<name>')`. Immutable after create.
Returns the full experiment row including groups, params, allocation, and lifecycle timestamps.
Use caseFetch one experiment to render the detail page or to inspect its current allocation and group weights.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque experiment id (`exp_…`) or the experiment's `name`.
Response · 200
Name
Type
Description
idrequired
string
Stable opaque experiment id (`exp_…`).
namerequired
string
Stable experiment key (a-z, 0-9, `_`/`-`, must start with letter/digit, max 64 chars). Used by SDKs as `Shipeasy.getExperiment(user, '<name>')`. Immutable after create.
Partial update. allocation_pct, groups, salt, universe, params are immutable while running — returns 409 if you try. Stop the experiment first.
Editing groups while in draft is fine; weights must still sum to 10000.
Use cases
Use case
Description
Example
Update metadata
description, tag, targeting_gate editable any time.
Ramp before launch
set allocation_pct while still in draft.
Tighten significance
significance_threshold (Pro+).
Rewire groups
replace groups wholesale while in draft; immutable once running.
—
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque experiment id.
Body
Name
Type
Description
name
string
Stable experiment key (a-z, 0-9, `_`/`-`, must start with letter/digit, max 64 chars). Used by SDKs as `Shipeasy.getExperiment(user, '<name>')`. Immutable after create.
description
string | null
—
tag
string | null
—
targeting_gate
string | null
—
allocation_pct
integer
Basis-points allocation (0–10000). Immutable while the experiment is running.
salt
string
Hash salt. Immutable while running.
universe
string
New universe name. Immutable while running. Returns `422` if the universe doesn't exist.
params
object
Map of param-name → scalar type. Defines the shape of `groups[].params`. Example: `{ headline: 'string', show_cta: 'bool' }`.
Replacement groups. Weights must sum to 10000. Immutable while running.
significance_threshold
number
—
min_runtime_days
integer
—
min_sample_size
integer
—
sequential_testing
boolean
—
Response · 200
Name
Type
Description
idrequired
string
Experiment id that was updated.
Example · 200
{
"id": "exp_01j7wb12c3d4e5f6g7h8j9k0l1"
}
DELETE/api/admin/experiments/{id}
Delete an experiment
Archives the experiment (soft-delete via status transition). Returns 409 if the experiment is still running — stop it first.
Use caseTear down an experiment after the analysis is signed off.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque experiment id.
Response · 200
Name
Type
Description
okrequired
true
—
Example · 200
{
"ok": true
}
POST/api/admin/experiments/{id}/status
Transition experiment status
Drives the experiment lifecycle. Allowed transitions:
- draft → running — starts allocation. Bumps the startedAt timestamp.
- running → stopped — halts allocation. Existing exposures stay in the dataset.
- stopped → archived — soft-delete.
- draft → archived — discard an unstarted experiment.
Restarting an archived experiment is not allowed; clone instead. Returns 409 on illegal transitions and 429 if the plan's experiments_running limit is exceeded on → running.
Use cases
Use case
Description
Example
Start
{ "status": "running" } after wiring up the SDK and verifying targeting on staging.
Stop
{ "status": "stopped" } once the experiment hits its min_runtime_days and conclusive results land.
Archive
{ "status": "archived" } to soft-delete after sign-off.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque experiment id.
Body
Name
Type
Description
statusrequired
"draft" | "running" | "stopped" | "archived"
Target status. Allowed transitions: `draft → running`, `running → stopped`, `stopped → archived`, `draft → archived`. Restarting an archived experiment is not allowed.
Returns the latest analysis output for the experiment — one row per metric/group/day, including sample size, mean, % delta vs. control, p-value, and a sample-ratio mismatch flag.
Use caseRender the results table on the experiment detail page or drive an automated decision once a goal metric reaches significance.
Requeues the daily analysis pass for this experiment outside the normal cron cadence. Useful after attaching a new metric or correcting an event taxonomy. The job runs asynchronously.
Use caseForce-refresh results after wiring up a new metric without waiting for the next nightly cron tick.
Returns a single page of configs ordered by updated_at desc, id desc. Each row includes the latest published version per env and any active drafts.
Use caseSnapshot every config in the project — e.g. CI check that asserts no env is stuck on a stale default or that every config has a published value on prod.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
limit
query
number
Max results per page (default 50, max 500).
cursor
query
string
Opaque pagination cursor from a prior page's `next_cursor`.
Creates a new config with the given schema. The initial value (or an empty object) is published as version 1 on every env.
Returns 409 if name already exists in the project, 400 if value doesn't validate against schema.
Use cases
Use case
Description
Example
Minimal create
name + schema. Initial value defaults to {}.
Seeded create
supply a flat value to publish the same object on every env.
Per-env seed
supply a { env: value } map for different per-env starting values.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
Body
Name
Type
Description
namerequired
string
Stable config key in `folder.name` form (two lowercase segments separated by a dot, e.g. `pricing.tiers`). Used by SDKs as `Shipeasy.getConfig('<name>')`. Immutable after create.
description
string
Optional free-form description shown in the dashboard. Max 512 chars.
schemarequired
object
JSON Schema (draft 2020-12) describing the shape of the config value. Top-level `type` must be `'object'`; every published value is validated against this schema.
value
any | object
Initial config value. Either a single JSON object applied to every env, or a `{ env: value }` map seeding per-env values. Must match `schema`. Defaults to `{}` on every env when omitted.
Response · 201
Name
Type
Description
idrequired
string
Newly assigned config id.
namerequired
string
Stable config key in `folder.name` form (two lowercase segments separated by a dot, e.g. `pricing.tiers`). Used by SDKs as `Shipeasy.getConfig('<name>')`. Immutable after create.
Returns config metadata plus the latest published values per env and any active draft values. Use this to fetch the JSON the editor renders.
Use caseFetch one config's current published values and any in-flight drafts.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque config id (`cfg_…`) or the config's `name`.
Response · 200
Name
Type
Description
idrequired
string
Stable opaque config id (`cfg_…`).
namerequired
string
Stable config key in `folder.name` form (two lowercase segments separated by a dot, e.g. `pricing.tiers`). Used by SDKs as `Shipeasy.getConfig('<name>')`. Immutable after create.
descriptionrequired
string | null
—
schemarequired
object
JSON Schema (draft 2020-12) describing the shape of the config value. Top-level `type` must be `'object'`; every published value is validated against this schema.
updatedAtrequired
string
ISO-8601 timestamp of last mutation.
envsrequired
object
Per-env latest published version metadata.
draftsrequired
object
Per-env active drafts (if any).
values
object
Per-env latest published values (only returned by `GET /{id}`, not list).
draftValues
object
Per-env draft values (only returned by `GET /{id}`).
Partial update. When value is supplied it is republished on every env (new version per env). When schema is supplied it replaces the current schema; every existing value is re-validated.
For env-scoped edits, use the draft/publish flow (PUT /{id}/drafts then POST /{id}/publish) instead.
Use cases
Use case
Description
Example
Republish flat value
{ "value": {…} } sets the same value on every env.
Schema migration
{ "schema": {…} } replaces the schema; existing values are re-validated.
Env-scoped edits
use PUT /{id}/drafts + POST /{id}/publish instead of PATCH.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque config id.
Body
Name
Type
Description
schema
object
Replacement schema. When supplied, the new schema is validated against every published value before it lands.
value
any
Flat value applied to **every** env. Publishes a new version per env. To target one env, use `PUT /{id}/drafts` then `POST /{id}/publish`.
Response · 200
Name
Type
Description
idrequired
string
Config id that was updated.
Example · 200
{
"id": "cfg_01j7wae5h6j7k8l9m0n1p2q3r4"
}
DELETE/api/admin/configs/{id}
Delete a dynamic config
Soft-deletes the config and rebuilds the project's flags KV blob.
Use caseTear down a config after its consumers have stopped reading it.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque config id.
Response · 200
Name
Type
Description
okrequired
true
—
Example · 200
{
"ok": true
}
PUT/api/admin/configs/{id}/drafts
Save a draft value
Stages a value for one env without publishing. The draft is validated against the config's current schema and stored alongside the baseVersion it was forked from.
Saving over an existing draft overwrites it. Use POST /{id}/publish to promote it to a new published version.
Use caseIterate on a config value on dev without affecting prod — preview in staging, then publish.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque config id.
Body
Name
Type
Description
envrequired
"dev" | "staging" | "prod"
Target environment. One of the project's configured envs (`dev`, `stage`, `prod`).
valuerequired
any
Draft value to stage on `env`. Validated against the config's current schema.
Response · 200
Name
Type
Description
idrequired
string
—
envrequired
"dev" | "staging" | "prod"
Target environment. One of the project's configured envs (`dev`, `stage`, `prod`).
Returns recent audit rows for one config (create, update, draft.save, publish, delete) ordered newest first. Use the limit query parameter to cap the result (1–100, default 20).
Use caseRender the activity panel in the config editor or drive a slack notification on publish events.
{
"data": [
{
"id": "ksw_01j7w9d8h2k4m6n8p0q2r4s6t8",
"name": "payments.checkout",
"description": "Master kill for the checkout flow. Trip to fall back to the legacy provider.",
"updatedAt": "2026-05-09T18:22:11.000Z",
"envs": {
"dev": {
"value": false,
"version": 3,
"publishedAt": "2026-05-09T18:22:11.000Z"
},
"stage": {
"value": false,
"version": 3,
"publishedAt": "2026-05-09T18:22:11.000Z"
},
"prod": {
"value": false,
"switches": {
"eu_region": true
},
"version": 5,
"publishedAt": "2026-05-09T18:22:11.000Z"
}
}
}
],
"next_cursor": null
}
POST/api/admin/killswitches
Create a killswitch
Creates a new killswitch with value (default false) applied to every env at version 1.
Returns 409 if name already exists in the project.
Use cases
Use case
Description
Example
Untripped create
{ "name": "payments.checkout" }. Provision the kill ahead of an incident.
Pre-tripped
{ "value": true } to ship the killswitch already engaged.
With switches
seed switches to carve out per-region/per-tenant kills from day one.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
Body
Name
Type
Description
namerequired
string
Stable killswitch key in `folder.name` form (two lowercase segments separated by a dot — e.g. `payments.checkout`). Immutable after create.
description
string
Optional free-form description shown in the dashboard. Max 512 chars.
value
boolean
Default value applied to every env at creation. Defaults to `false`. Use `true` to ship the killswitch pre-tripped.
switches
object
Initial per-switch overrides applied to every env. Empty/omitted leaves the killswitch with only the flat `value`.
Response · 201
Name
Type
Description
idrequired
string
Newly assigned killswitch id.
namerequired
string
Stable config key in `folder.name` form (two lowercase segments separated by a dot, e.g. `pricing.tiers`). Used by SDKs as `Shipeasy.getConfig('<name>')`. Immutable after create.
Returns the killswitch metadata plus the latest published value/switches/version per env.
Use caseFetch the current state of one killswitch — e.g. to verify a trip propagated before declaring an incident mitigated.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque killswitch id (`ksw_…`).
Response · 200
Name
Type
Description
idrequired
string
Stable opaque killswitch id.
namerequired
string
Stable config key in `folder.name` form (two lowercase segments separated by a dot, e.g. `pricing.tiers`). Used by SDKs as `Shipeasy.getConfig('<name>')`. Immutable after create.
descriptionrequired
string | null
Free-form description or `null`.
updatedAtrequired
string
ISO-8601 timestamp of last mutation.
envsrequired
object
Per-env latest value, switches, version, and publish timestamp.
Example · 200
{
"id": "ksw_01j7w9d8h2k4m6n8p0q2r4s6t8",
"name": "payments.checkout",
"description": "Master kill for the checkout flow. Trip to fall back to the legacy provider.",
"updatedAt": "2026-05-09T18:22:11.000Z",
"envs": {
"dev": {
"value": false,
"version": 3,
"publishedAt": "2026-05-09T18:22:11.000Z"
},
"stage": {
"value": false,
"version": 3,
"publishedAt": "2026-05-09T18:22:11.000Z"
},
"prod": {
"value": false,
"switches": {
"eu_region": true
},
"version": 5,
"publishedAt": "2026-05-09T18:22:11.000Z"
}
}
}
PATCH/api/admin/killswitches/{id}
Update a killswitch
Partial update applied to every env. Setting value/switches publishes a new version per env. Description-only patches don't bump versions.
To change a single switch on a single env, use PUT /{id}/switch instead.
Use cases
Use case
Description
Example
Trip everywhere
{ "value": true }. Kills the feature across dev/stage/prod in one call.
Untrip everywhere
{ "value": false }.
Replace switches
send the full new map; per-key edits use PUT /{id}/switch.
Update description
metadata-only patches don't bump versions.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque killswitch id.
Body
Name
Type
Description
description
string | null
New description, or `null` to clear it. Max 512 chars.
value
boolean
Flat value applied to every env. Publishes a new version per env when set. Omit to leave values unchanged.
switches
object
Replace the switches map wholesale on every env. To edit a single entry on a single env use `PUT /{id}/switch` instead.
Response · 200
Name
Type
Description
idrequired
string
Killswitch id that was updated.
Example · 200
{
"id": "ksw_01j7w9d8h2k4m6n8p0q2r4s6t8"
}
DELETE/api/admin/killswitches/{id}
Delete a killswitch
Soft-deletes the killswitch and rebuilds the project's flags KV blob so SDKs stop seeing it.
Use caseTear down a killswitch after the feature it protected has been removed.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque killswitch id.
Response · 200
Name
Type
Description
okrequired
true
—
Example · 200
{
"ok": true
}
PUT/api/admin/killswitches/{id}/switch
Set one switch entry
Sets or updates a single switchKey on a single env. Publishes one new version on that env only — other envs untouched.
Use this for surgical per-env, per-key flips during incident response (e.g. trip eu_region on prod without touching the flat value or other envs).
Creates a new universe. Only name is required — unit_type defaults to user_id and holdout_range defaults to null (no holdout).
Returns 409 if name already exists in the project. Returns 403 if you supply holdout_range on a plan below Pro.
Use cases
Use case
Description
Example
Default universe
{ "name": "primary_users" }. Per-user randomisation, no holdout.
—
Reserved holdout
supply holdout_range to carve out a measurement slice excluded from all experiments.
Account-level
unit_type: 'account_id' so multi-seat accounts see one consistent variant.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
Body
Name
Type
Description
namerequired
string
Stable universe key referenced by experiments via `universe: '<name>'`. Lowercase letters, digits, `_` or `-`, max 64 chars. Immutable after create.
unit_type
string
Unit of randomisation. Typically `user_id`. Use `account_id` to keep whole accounts in the same group across an experiment. default: "user_id"
holdout_range
array<any> | null
Inclusive `[lo, hi]` bucket range (0–9999) reserved as the **holdout** — callers hashed into this slice are excluded from every experiment in the universe. `null` disables the holdout. Pro plan or higher required. default: null
Response · 201
Name
Type
Description
idrequired
string
Newly assigned universe id.
namerequired
string
Stable universe key referenced by experiments via `universe: '<name>'`. Lowercase letters, digits, `_` or `-`, max 64 chars. Immutable after create.
Partial update. Only holdout_range is mutable — name and unit_type are immutable after create.
Pass "holdout_range": null to remove an existing holdout.
Use cases
Use case
Description
Example
Adjust holdout
change the reserved measurement slice without recreating experiments.
Remove holdout
{ "holdout_range": null }.
Parameters
Name
In
Type
Description
X-Project-Idrequired
header
string
Project to scope this request to.
idrequired
path
string
Stable opaque universe id (`uni_…`).
Body
Name
Type
Description
holdout_range
array<any> | null
Inclusive `[lo, hi]` bucket range (0–9999) reserved as the **holdout** — callers hashed into this slice are excluded from every experiment in the universe. `null` disables the holdout. Pro plan or higher required.
Response · 200
Name
Type
Description
idrequired
string
Universe id that was updated.
Example · 200
{
"id": "uni_01j7w8a1b2c3d4e5f6g7h8i9j0"
}
DELETE/api/admin/universes/{id}
Delete a universe
Soft-deletes the universe. Returns 409 if any non-archived experiment still references it — archive those experiments first.
Use caseTear down a universe after every experiment that used it has been archived.