MCP reference
Auto-generated reference for the @shipeasy/mcp server — every tool, nested under its group, with title, full description, parameters, and error codes.
Every tool below is generated from the MCP server's own tool catalog (so it matches what the server advertises), nested under its group the same way the CLI reference nests commands, and enriched from the OpenAPI spec with each group's description plus every tool's title, full description, and error codes.
New to the MCP server? Start with the MCP guide for installation and connecting your agent — this page is the exhaustive tool-by-tool reference.
Errors
Every registry-backed tool resolves to an admin-API call that, on failure, returns the uniform error envelope below. The MCP server surfaces it to the client as a tool error.
{ "error": "human-readable message", "code": "ERROR_CODE", "detail": "optional context" }Every such tool can return these: UNAUTHORIZED, FORBIDDEN. Each tool's own Errors note lists only the codes beyond this common set.
All error codes:
| Code | Meaning |
|---|---|
BAD_REQUEST | Malformed request (bad JSON, missing project scope). |
UNAUTHORIZED | Missing or invalid admin SDK key. |
FORBIDDEN | Key is valid but not allowed to act on this project. |
PLAN_REQUIRED | The requested feature requires a higher plan tier (e.g. sequential testing, custom alpha, holdout, group count). |
NOT_FOUND | The resource does not exist or is not visible to the caller. |
ALREADY_EXISTS | A resource with this name already exists in the project. |
INVALID_TRANSITION | The requested lifecycle transition is not allowed from the current state. |
IMMUTABLE_FIELD | A field that is immutable in the current state was modified (e.g. editing allocation while running). |
READ_ONLY | The resource is a read-only built-in (e.g. a built-in gate-rule template) and cannot be modified or deleted. |
REFERENCED_IN_USE | The resource cannot be archived/deleted while another resource still references it. |
VALIDATION | The request body failed structural (schema) validation. |
REFERENCED_NOT_FOUND | A referenced entity (universe, metric, gate, event) does not exist. |
GROUPS_WEIGHT_SUM | Experiment group weights must sum to 10000 (basis points). |
EVENT_PENDING | The referenced event is still pending review and cannot back a metric yet. |
INTERNAL | Unexpected server error. |
PLAN_LIMIT | The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource. |
EXPERIMENT_NO_GOAL_METRIC | The experiment has no goal metric set, which the requested action requires. |
EXPERIMENT_ARCHIVED_RESTART | An archived experiment cannot be restarted. |
EXPERIMENT_RESTORE_INVALID | The experiment cannot be restored from its current state. |
EXPERIMENT_NOT_RUNNING | The action requires the experiment to be running. |
EXPERIMENT_RUNNING_ARCHIVE | A running experiment cannot be archived — stop it first. |
EXPERIMENT_IMMUTABLE_FIELD | A field that is immutable while the experiment is running was modified. |
METRIC_NOT_FOUND | The referenced metric does not exist or is not visible to the caller. |
METRIC_UNKNOWN_ID | The supplied metric id is malformed or not recognised. |
AGENT_NOT_CONNECTED | The named AI agent type has no connected trigger connector in this project — list the available agents (ops agents list / GET /api/admin/agent-profiles) and use one of those, or connect the agent under Settings → Triggers. |
Hand-written tools (projects_upsert and auth) layer the .shipeasy bind or the device-auth flow on top of the admin API rather than being plain spec calls, so they don't use this envelope. All filesystem / AST tooling (project detection, i18n source scanners / codemods / loader install) now lives in the shipeasy CLI, not this MCP server.
Release
Feature delivery — flags, kill switches, dynamic configs, A/B experiments, and the universes they bucket in.
Flags
Feature gates: boolean flags evaluated at runtime against project rules + a percentage rollout.
Identity. Each gate is keyed by a stable name (a-z, 0-9, _/-, max 64 chars) which is what SDKs pass to Shipeasy.checkGate(user, '<name>'). The name is immutable — rename means delete + recreate.
Evaluation model. A gate returns true when (a) enabled is true, and (b) the caller satisfies the gate's rules. There are two evaluation shapes:
- Flat —
rules(AND-combined predicates) gate the caller, thenrollout_pct(basis points, 0–10000) hashes them into a bucket. Used for simpleis in X% rolloutgates. - Gatekeeper stack — an ordered array of
conditionandrolloutsub-gates, evaluated top-to-bottom; first match wins. Used to expressinternal-only ∪ 1% beta ∪ 50% publicin one gate. Whenstackis present it takes precedence over the flat fields.
Rules. Each rule is { attr, op, value }. Supported ops: eq, neq, in, not_in, gt, gte, lt, lte, contains, regex. Attribute names match the keys on the SDK evaluation context (e.g. country, plan, email).
Rollout basis points. rollout_pct is in basis points, not percent. 0 = 0%, 100 = 1%, 5000 = 50%, 10000 = 100%. This allows sub-1% precision (e.g. 7 = 0.07%).
Lifecycle. Create dark (rollout_pct: 0) → attach rules → ramp via PATCH → flip kill-switch via disable/enable → delete once retired. Deletion is blocked while a running experiment references the gate as a targeting gate.
release_flags_activity
List gate activity
Returns recent audit rows for one gate (create, update, enable, disable, delete) ordered newest first. Use the limit query parameter to cap the result (1–100, default 20).
Render the activity feed in the gate detail panel or answer "who ramped this gate, and when?" during an incident review.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
limit | optional | integer | Max rows to return (1–100). Defaults to 20. (default 20; 1–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_flags_archive
Delete a feature gate
Soft-deletes the gate. Returns 409 if the gate is still referenced by a running experiment as a targeting gate — stop the experiment first.
Tear down a gate after a feature has fully shipped and the rollout flag is no longer needed.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.REFERENCED_IN_USE— The resource cannot be archived/deleted while another resource still references it.
release_flags_create
Create a feature gate
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).
- Dark create + ramp later —
{ "name": "checkout_v2" }at 0% rollout. Ramp via PATCH after deploy validation. - Targeted rollout — supply
rulesto gate the caller (e.g. onlyplan = prousers) plus arollout_pctto bucket within that audience. - Gatekeeper stack — supply
stackinstead ofrules/rollout_pctforinternal ∪ beta ∪ publicfall-through. Stack entries evaluated top-to-bottom; first match wins. - Dashboard metadata — populate
title,description,folder,group,owner_emailso the admin UI is self-documenting from day one. - Disabled on create — pre-provision with
enabled: falsefor a future launch; flip on withPOST /{id}/enableat go-live.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Stable gate key used by SDKs (Shipeasy.checkGate(user, '<name>')). Single segment or folder.name. Lowercase letters, digits, _ or -; max 128 chars. Immutable after create — rename = delete + recreate. (length 0–128; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$) |
type | optional | "targeting" | "holdout" | Gate kind. targeting (default) is a normal flag with the full builder. holdout is a restricted flag — only a public rollout % and a whitelist are allowed; attribute rules and a gatekeeper stack are rejected. Used as an experiment's holdout_gate. (default "targeting") |
enabled | optional | 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 | optional | integer | Initial rollout in basis points (0–10000 = 0%–100%) — 100 here means 1%, not 100%. Use rollout_percent (0–100) below if you'd rather think in percent. Use 0 to create the gate dark and ramp via PATCH after deploy validation. (default 0; 0–10000) |
rollout_percent | optional | number | Initial rollout as a percentage (0–100, fractional ok). Friendlier alias for rollout_pct; converted internally to basis points (e.g. 100 here = 10000 bp = 100%). If both rollout_pct and rollout_percent are set, rollout_percent wins. (0–100) |
rules | optional | object[] | 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 | optional | 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. (length 1–64) |
stack | optional | any | Optional gatekeeper stack. When provided, takes precedence over rules + rollout_pct at evaluation time. Omit (or pass null) for a flat gate. |
title | optional | string | Human-readable title shown in the dashboard. Free-form, no key format constraint. (length 0–140) |
description | optional | string | Long-form description / runbook. Markdown is rendered in the dashboard. (length 0–2000) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
group | optional | string | Group label for dashboard organisation (e.g. team or product area). (length 0–64) |
owner_email | optional | string | Owner contact. Displayed verbatim; not used for auth. (length 0–190) |
listToken | optional | string | REQUIRED. The listToken returned by the most recent release_flags_list call. It proves you listed existing release flags and confirmed this one doesn't already exist before creating it. Call release_flags_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.
release_flags_disable
Disable a gate
Sets enabled: false so the gate evaluates to false for every caller, regardless of rollout_pct or rules. Use as a quick kill switch.
Flip a gate off in production without redeploying — the canonical kill-switch flow.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_flags_enable
Enable a gate
Sets enabled: true. The current rollout_pct is preserved.
Re-enable a previously disabled gate without re-issuing a full update.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_flags_get
Get one gate
Returns the full gate row — including the gatekeeper stack, resolved creator/last-editor emails, and the edit version — for one gate, addressed by id or name.
Inspect a single gate's current rollout, rules, and stack before editing it, without paging through the whole list.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_flags_list
List feature gates
Returns a single page of gates ordered by updated_at desc, id desc. Use the cursor query parameter to paginate.
Snapshot 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
| Parameter | Type | Description | |
|---|---|---|---|
limit | optional | integer | Page size (1–500). Defaults to 100. (default 100; 1–500) |
cursor | optional | string | Opaque cursor returned in the previous page's next_cursor. Omit for the first page. |
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
release_flags_update
Update a feature gate
Partial update — only supplied fields change. Array fields (rules, stack) replace wholesale; there is no merge or append.
name and the gate id are immutable. The response carries only { id } — re-fetch via GET /api/admin/gates for the new row.
- Ramp rollout —
{ "rollout_pct": 5000 }for 50%. Basis points (0–10000);100= 1%. - Kill switch —
{ "enabled": false }. Forces evaluation tofalsefor every caller regardless of rules/rollout. Re-enable withPOST /{id}/enableor{ "enabled": true }. - Modify a rule's
inset — send the full newrulesarray. To add'GB'to['US','CA']:{ "rules": [{ "attr": "country", "op": "in", "value": ["US","CA","GB"] }] }. No per-rule patch endpoint. - Add targeting from scratch —
{ "rules": [{ "attr": "email", "op": "regex", "value": "@acme\\.com$" }] }. - Switch to gatekeeper stack — send a non-null
stack. To revert to flat eval, send{ "stack": null }. - Update metadata — any subset of
title,description,folder,group,owner_email.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
type | optional | "targeting" | "holdout" | Gate kind. Switching to holdout requires the gate carry only a public rollout % + whitelist (attribute rules / stack are rejected). |
rollout_pct | optional | integer | New rollout in basis points (0–10000 = 0%–100%) — 100 here means 1%. Use rollout_percent (0–100) below for percent. Omit both to leave unchanged. (0–10000) |
rollout_percent | optional | number | New rollout as a percentage (0–100). Friendlier alias for rollout_pct; converted internally. Wins over rollout_pct if both are supplied. Omit both to leave unchanged. (0–100) |
rules | optional | object[] | 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 | optional | boolean | Master switch. false makes the gate evaluate to false for every caller regardless of rollout_pct, rules, or stack — use as kill switch. |
stack | optional | any | Replaces the gatekeeper stack wholesale. Send null to revert to flat rules + rollout_pct evaluation. |
title | optional | string | Human-readable title shown in the dashboard. Free-form, no key format constraint. (length 0–140) |
description | optional | string | Long-form description / runbook. Markdown is rendered in the dashboard. (length 0–2000) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
group | optional | string | Group label for dashboard organisation (e.g. team or product area). (length 0–64) |
owner_email | optional | string | Owner contact. Displayed verbatim; not used for auth. (length 0–190) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_flags_whitelist
Read a gate's whitelist
Returns the gate's whitelist — the always-first allowlist that admits the listed identities before any targeting rule or percentage rollout is evaluated.
A gate with no whitelist returns entries: [] (and the default attr), never a 404 — so a caller can read-then-write without special-casing the empty gate.
Check whether an account is already let through before adding it.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_flags_whitelist_add
Add entries to a gate's whitelist
Adds identities to the gate's whitelist, creating the block if the gate doesn't have one yet. Entries already on the list are skipped, so the call is idempotent and safe to retry.
Adding to a gate that already has a whitelist keyed on the other attribute is rejected (409) rather than silently re-keying the entries already there — use PUT to switch attr deliberately.
Let one more customer into a private beta without reading the current list first.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
attr | optional | any | Identity attribute to match on. Only honoured when the gate has no whitelist yet (this call creates it); passing an attribute that disagrees with an existing whitelist is a 409 rather than a silent re-key of the entries already there. |
entries | required | string[] | Identities to admit. Already-listed entries are skipped, so the call is idempotent. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.IMMUTABLE_FIELD— A field that is immutable in the current state was modified (e.g. editing allocation while running).VALIDATION— The request body failed structural (schema) validation.
release_flags_whitelist_remove
Remove entries from a gate's whitelist
Removes identities from the gate's whitelist. Entries that aren't on the list are skipped, so the call is idempotent.
Removing the last entry leaves an empty whitelist block in place; to drop the block itself use PUT with entries: [].
Revoke one beta tester's access without touching anyone else's.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
entries | required | string[] | Identities to stop admitting. Entries that aren't listed are skipped, so the call is idempotent. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_flags_whitelist_set
Replace a gate's whitelist
Replaces the gate's whole whitelist with entries, creating the block if the gate didn't have one. Idempotent — the same call twice leaves the same list.
This is the only whitelist call that can switch attr (email ⇄ user_id) or clear the block: entries: [] removes the whitelist from the gate entirely.
- Pin an exact list —
{ "entries": ["alice@acme.dev", "bob@acme.dev"] }. - Switch to user ids —
{ "attr": "user_id", "entries": ["usr_123"] }. - Drop the whitelist —
{ "entries": [] }.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
attr | optional | any | Identity attribute to match on. Defaults to the whitelist's current attribute, or email when the gate has no whitelist yet. |
entries | required | string[] | The complete whitelist after the call. Pass [] to remove the whitelist from the gate entirely. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Templates
Targeting-rule templates: reusable { attr, op, value } rule definitions
(country, email-domain, region presets, …). Read-only built-ins ship with
the platform; each project can also save its own. To target by
country/plan/region, list templates, copy the matching template's rules,
substitute the concrete value(s), and pass them to release flags create.
release_flags_templates_archive
Delete a gate template
Soft-deletes (archives) a customer template. Returns 409 if id names a read-only built-in template.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.READ_ONLY— The resource is a read-only built-in (e.g. a built-in gate-rule template) and cannot be modified or deleted.
release_flags_templates_create
Create a gate template
Creates a per-project (customer) targeting-rule template. Built-ins are read-only and cannot be created here. Returns 409 if a template with this name already exists in the project.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Human label. Unique per project. (length 1–140) |
description | optional | string | One-liner shown in pickers and matched by the list query filter. (default ""; length 0–2000) |
category | optional | "condition" | "rollout" | — (default "condition") |
icon_key | optional | string | Display-only icon hint. (length 0–64) |
auto | optional | boolean | Mark the attribute as request-derived (resolved at the SDK edge). (default false) |
rules | required | object[] | The rule definition captured by the template. |
listToken | optional | string | REQUIRED. The listToken returned by the most recent release_flags_templates_list call. It proves you listed existing release flags templates and confirmed this one doesn't already exist before creating it. Call release_flags_templates_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.
release_flags_templates_get
Get one gate template
Returns a single template by its id — a built-in slug (country) or a customer gtpl_… id.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_flags_templates_list
List gate templates
Returns the merged targeting-rule template catalog — read-only built-ins first (the @team/@owner audience aliases, country, email-domain, region presets, …), then this project's customer templates. Each item carries a rules: [{ attr, op, value }] definition; the alias templates carry a symbol value (email in ["@team"]) that the SDK expands to the resolved email list at rebuild.
Turn "launch X in country Y" into a gated flag: list templates (optionally with q), take the matching template's rules, substitute the concrete value(s), and pass them as the rules arg of release_flags_create.
The catalog is small and bounded, so the full merged set is returned in one page — this endpoint is not paginated (next_cursor is always null; there are no limit/cursor params).
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
query | optional | string | Deprecated alias for q, kept working for one release. Prefer q. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
release_flags_templates_update
Update a gate template
Partial update of a customer template. rules replaces the list wholesale. Returns 409 if id names a read-only built-in template.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
name | optional | string | — (length 1–140) |
description | optional | string | — (length 0–2000) |
category | optional | "condition" | "rollout" | — |
icon_key | optional | any | — |
auto | optional | boolean | — |
rules | optional | object[] | — |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.READ_ONLY— The resource is a read-only built-in (e.g. a built-in gate-rule template) and cannot be modified or deleted.VALIDATION— The request body failed structural (schema) validation.
Attributes
Targeting attributes: the auto-inferred schema of user-context keys the platform has observed in evaluation calls. Read-only — populated by the SDK hot path, surfaced here so you can see which keys (and value types) are available when writing gate/experiment targeting rules.
release_flags_attributes_archive
Archive a targeting attribute
Soft-deletes (archives) a targeting attribute.
Retire an attribute no targeting rule references anymore (the user-facing verb is archive).
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_flags_attributes_create
Declare a targeting attribute
Declare a targeting attribute the SDK reports and gates/experiments can target. type: enum requires enum_values.
Register a plan or country attribute so targeting rules can reference it.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Attribute key (lowercase alphanumeric start, then letters/digits/_/-; max 64 chars). Immutable after create. (pattern ^[a-z0-9][a-z0-9_-]{0,63}$) |
type | required | "string" | "number" | "boolean" | "enum" | "date" | Declared value type of a targeting attribute. |
enum_values | optional | any | Allowed values when type is enum (required in that case — 422 otherwise); null for non-enum types. (default null) |
required | optional | boolean | Whether the attribute must be present on the evaluation context. (default false) |
description | optional | string | Optional human note shown in the dashboard. |
sdk_path | optional | string | Optional dotted path the SDK reads the value from. |
listToken | optional | string | REQUIRED. The listToken returned by the most recent release_flags_attributes_list call. It proves you listed existing release flags attributes and confirmed this one doesn't already exist before creating it. Call release_flags_attributes_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.
release_flags_attributes_get
Get a targeting attribute
Fetch one targeting attribute by id.
Inspect an attribute's declared type + allowed values before editing it.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_flags_attributes_list
List targeting attributes
Returns every auto-inferred targeting attribute in the project — the name and (when known) the value type — for building gate/experiment targeting rules.
Discover which user-context keys are available before authoring a targeting rule, instead of guessing attribute names.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
release_flags_attributes_update
Update a targeting attribute
Update a targeting attribute's type, allowed values, required flag, description, or SDK path. name is immutable.
Add an allowed value to an enum attribute, or flip its required flag.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
type | optional | "string" | "number" | "boolean" | "enum" | "date" | Declared value type of a targeting attribute. |
enum_values | optional | any | Replacement allowed values (for enum), or null to clear. |
required | optional | boolean | Whether the attribute must be present on the evaluation context. |
description | optional | string | Optional human note shown in the dashboard. |
sdk_path | optional | string | Optional dotted path the SDK reads the value from. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Killswitch
Killswitches: per-env boolean overrides for kill-style operational toggles. Optimised for incident response — no rules, no rollout, just a flat boolean (plus optional per-key overrides) versioned per environment.
Identity. Each killswitch is keyed by name in folder.name form (e.g. payments.checkout). Immutable after create.
Per-env values. Every killswitch stores one version stream per env (dev, stage, prod). A PATCH with value/switches applies to every env in one shot (publishes a new version per env). To touch a single env, use PUT /{id}/switch and friends.
Switches map. Optional switches: { key: bool } overrides the flat value for specific named call sites — useful for region/feature-scoped kills.
Versioning. Each publish (create, update, set-switch, unset-switch) bumps the per-env version monotonically. SDKs deliver the latest published version.
release_killswitch_archive
Delete a killswitch
Soft-deletes the killswitch and rebuilds the project's flags KV blob so SDKs stop seeing it.
Tear down a killswitch after the feature it protected has been removed.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_killswitch_create
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.
- 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
switchesto carve out per-region/per-tenant kills from day one.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Stable config/killswitch key in folder.name form (two lowercase segments separated by a dot, e.g. pricing.tiers). Immutable after create. (length 0–128; pattern ^(?:_default|[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$) |
description | optional | string | Optional free-form description shown in the dashboard. Max 512 chars. (length 0–512) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
value | optional | boolean | Default value applied to every env at creation. Defaults to false. Use true to ship the killswitch pre-tripped. |
switches | optional | object | Initial per-switch overrides applied to every env. Empty/omitted leaves the killswitch with only the flat value. |
listToken | optional | string | REQUIRED. The listToken returned by the most recent release_killswitch_list call. It proves you listed existing release killswitch and confirmed this one doesn't already exist before creating it. Call release_killswitch_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.
release_killswitch_get
Get one killswitch
Returns the killswitch metadata plus the latest published value/switches/version per env.
Fetch the current state of one killswitch — e.g. to verify a trip propagated before declaring an incident mitigated.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_killswitch_list
List killswitches
Returns a single page of killswitches ordered by updated_at desc, id desc. Each row includes the latest published value/switches/version per env.
Snapshot every killswitch in the project — e.g. to render an incident-response runbook listing every kill and its current trip state.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
limit | optional | integer | Page size (1–500). Defaults to 100. (default 100; 1–500) |
cursor | optional | string | Opaque cursor returned in the previous page's next_cursor. Omit for the first page. |
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
release_killswitch_set
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).
- Trip a region —
{ "env": "prod", "switchKey": "eu_region", "value": true }. - Untrip without removing — same payload with
value: false. To remove the entry entirely useDELETE /{id}/switch.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
env | required | "dev" | "staging" | "prod" | Target environment. One of the project's configured envs (dev, staging, prod). |
switchKey | required | string | Switch key to set. (length 0–64; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$) |
value | required | boolean | New boolean value for this switchKey on this env. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_killswitch_set_value
Set the flat value on one env
Sets the flat value on a single env, publishing one new version on that env only. switches and other envs are untouched.
Use this to trip (or untrip) a killswitch on one environment without replacing its per-key overrides.
- Trip on prod —
{ "env": "prod", "value": true }. - Untrip on prod —
{ "env": "prod", "value": false }.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
env | required | "dev" | "staging" | "prod" | Target environment. One of the project's configured envs (dev, staging, prod). |
value | required | boolean | Flat boolean to publish on env. Publishes a new version on that env only. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_killswitch_toggle
Toggle a killswitch or one of its switches
Flips a killswitch on one environment and publishes a new version there. This is the one-call incident verb: it reads the current value, flips it, and publishes, so you don't have to fetch the killswitch first.
Every body field is optional, which is what makes the call widen cleanly:
- Flip the killswitch —
{}. Flips the flatvalueonprod. - Flip one sub-switch —
{ "switchKey": "eu_region" }. Flips that entry onprod, creating it (fromfalse) if it isn't in the map yet. - Set it idempotently —
{ "switchKey": "eu_region", "value": true }. Publishes exactly that value, so a retried call can't undo the first one. Anullvaluemeans "flip", not "set to null". - Choose the environment — add
"env": "staging". Omitted,envisprod.
The response reports both previous and value, so a caller that asked for a flip can see what it actually changed.
Prefer this over PUT /{id}/value and PUT /{id}/switch unless you specifically need those endpoints' unconditional set semantics.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
switchKey | optional | any | Which target to flip. Omit (or null) to flip the killswitch's own flat value; name a switch key to flip that nested sub-switch instead, creating the entry if it doesn't exist yet. |
value | optional | any | The value to publish. Omit (or null) to flip whatever is stored now — read-modify-write in one call. Pass an explicit true/false to make the call idempotent, so a retry can't undo the first attempt. |
env | optional | any | Environment to publish on. Defaults to prod — the environment an incident response means when it says "kill it". |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_killswitch_unset
Remove one switch entry
Removes a single switchKey from the switches map on a single env. Publishes a new version on that env.
Returns { removed: false } if the entry didn't exist (idempotent no-op).
Clean up a per-region override after the incident is resolved so the flat value governs again.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
env | required | "dev" | "staging" | "prod" | Target environment. One of the project's configured envs (dev, staging, prod). |
switchKey | required | string | Switch key to remove. (length 0–64; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_killswitch_update
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.
- 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
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
description | optional | any | New description, or null to clear it. Max 512 chars. |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
value | optional | boolean | Flat value applied to every env. Publishes a new version per env when set. Omit to leave values unchanged. |
switches | optional | object | Replace the switches map wholesale on every env. To edit a single entry on a single env use PUT /{id}/switch instead. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Configs
Dynamic configs: JSON-Schema-validated structured values delivered to SDKs and editable per environment with a draft/publish workflow.
Identity. Each config is keyed by name in folder.name form (e.g. pricing.tiers). Immutable after create.
Schema-first. Every config carries a JSON Schema (draft 2020-12, top-level type: 'object'). Every published value is validated against it.
Drafts → publish. Per-env edits go through PUT /{id}/drafts (stages a value) then POST /{id}/publish (promotes to a new version). The flat PATCH /{id} republishes on every env in one shot — bypassing drafts.
Versioning. Each publish bumps the per-env version monotonically. SDKs deliver the latest published version for each env.
release_configs_archive
Delete a dynamic config
Soft-deletes the config and rebuilds the project's flags KV blob.
Tear down a config after its consumers have stopped reading it.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_configs_create
Create a dynamic config
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.
- Minimal create —
name+schema. Initial value defaults to{}. - Seeded create — supply a flat
valueto publish the same object on every env. - Per-env seed — supply a
{ env: value }map undervalue, or pass the env keysdev/staging/proddirectly (each overridesvaluefor that env and is published at version 1).
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Stable config/killswitch key in folder.name form (two lowercase segments separated by a dot, e.g. pricing.tiers). Immutable after create. (length 0–128; pattern ^(?:_default|[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$) |
description | optional | string | Optional free-form description shown in the dashboard. Max 512 chars. (length 0–512) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
schema | required | 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 | optional | 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. |
dev | optional | object | Seed the dev env's initial value (version 1), overriding value for dev. Published immediately. Must match schema. |
staging | optional | object | Seed the staging env's initial value (version 1), overriding value for staging. Published immediately. Must match schema. |
prod | optional | object | Seed the prod env's initial value (version 1), overriding value for prod. Published immediately. Must match schema. |
listToken | optional | string | REQUIRED. The listToken returned by the most recent release_configs_list call. It proves you listed existing release configs and confirmed this one doesn't already exist before creating it. Call release_configs_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.
release_configs_get
Get one config
Returns config metadata plus the latest published values per env and any active draft values. Use this to fetch the JSON the editor renders.
Fetch one config's current published values and any in-flight drafts.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_configs_list
List dynamic configs
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.
Snapshot 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
| Parameter | Type | Description | |
|---|---|---|---|
limit | optional | integer | Page size (1–500). Defaults to 100. (default 100; 1–500) |
cursor | optional | string | Opaque cursor returned in the previous page's next_cursor. Omit for the first page. |
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
release_configs_update
Update a dynamic config
Partial update. When value is supplied it is republished on every env (new version per env). A per-env key (dev/staging/prod) publishes a new version to only that env, immediately, overriding value for it. When schema is supplied it replaces the current schema; every existing value is re-validated.
- Republish flat value —
{ "value": {…} }sets the same value on every env. - Publish one env —
{ "prod": {…} }publishes a new version to prod only, instantly. - Schema migration —
{ "schema": {…} }replaces the schema; existing values are re-validated.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
schema | optional | object | Replacement schema. When supplied, the new schema is validated against every published value before it lands. |
value | optional | object | Flat value applied to every env. Publishes a new version per env. To publish one env only, pass that env's key (dev/staging/prod) instead. |
dev | optional | object | Publish a new version to the dev env only, immediately (no draft). Overrides value for dev. Must match the effective schema. |
staging | optional | object | Publish a new version to the staging env only, immediately (no draft). Overrides value for staging. Must match the effective schema. |
prod | optional | object | Publish a new version to the prod env only, immediately (no draft). Overrides value for prod. Must match the effective schema. |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_configs_update_schema
Update a config schema
Replaces a config's JSON Schema in place. Every existing published value is re-validated against the new schema before it lands; the update fails if any value no longer validates.
Evolve a config's shape (add/remove a field) without republishing values.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
schema | required | object | Replacement JSON Schema (draft 2020-12). Validated against every published value before it lands. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Experiments
A/B/n experiments: randomised group assignment plus the analysis pipeline (t-test, sequential testing, SRM detection) on top of a universe.
Identity. Stable name (a-z, 0-9, _/-, max 64 chars). Immutable after create.
Lifecycle. draft → running → stopped → archived. Transition via POST /{id}/status. An archived experiment that never started can be restored with archived → draft; restarting an archived experiment directly is not allowed.
Allocation. allocation_pct (basis points, 0–10000) is the share of the targeted audience enrolled; groups[].weight (must sum to 10000) splits the enrolled audience. targeting_gate narrows the eligible audience before allocation.
Immutable while running. allocation_pct, groups, salt, universe, params cannot be edited on a running experiment — stop it first.
Metrics. Attach via POST /{id}/metrics. Each metric has a role: goal drives the decision, guardrail blocks ship on regression, secondary is informational.
Analysis. Daily cron writes results to D1. Read via GET /{id}/results (latest per metric/group/day) or GET /{id}/timeseries (full history). POST /{id}/reanalyze requeues the analysis pass.
release_experiments_archive
Delete an experiment
Archives the experiment (soft-delete via status transition). Returns 409 if the experiment is still running — stop it first.
Tear down an experiment after the analysis is signed off.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.INVALID_TRANSITION— The requested lifecycle transition is not allowed from the current state.
release_experiments_create
Create an experiment
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.
- Minimal 50/50 —
name+universe+ two equal-weight groups. - Targeted rollout — supply
targeting_gateto restrict the eligible audience andallocation_pctto enrol a slice of it. - Multivariant — three or more groups with weights summing to 10000.
- Sequential testing —
sequential_testing: truefor Premium plans.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Stable experiment key. Single segment or folder.name (a-z, 0-9, _/-; max 128 chars). Used by SDKs as Shipeasy.getExperiment(user, '<name>'). Immutable after create. (length 0–128; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$) |
description | optional | any | Free-form description. Max 2000 chars, markdown rendered in the dashboard. (default null) |
hypothesis | optional | any | Hypothesis statement shown in the editor. Display-only. (default null) |
tag | optional | any | Short tag chip rendered next to the name. Display-only. (default null) |
owner_email | optional | any | Owner email. Display-only. (default null) |
audience | optional | any | Audience label shown in the editor. Display-only. (default null) |
bucket_by | optional | any | — (default null) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
universe | required | string | Name of an existing universe in the project. Returns 422 if the universe doesn't exist. (length 1–∞) |
targeting_gate | optional | any | Optional gate name (a targeting-type flag). Only callers that pass the gate are enrolled in the experiment. (default null) |
holdout_gate | optional | any | Optional per-experiment holdout gate — the name of a holdout-type flag (public % + whitelist). A caller the flag passes is held out (never assigned, sees the universe defaults). Distinct from the universe-level holdout. (default null) |
allocation_pct | optional | integer | Share of the (gated) audience allocated to the experiment, in basis points (0–10000 = 0%–100%). 0 = unallocated. Under pooled assignment this is the size of the universe-pool slice claimed. Use allocation_percent (0–100) below to think in percent. Immutable while the experiment is running. (default 0; 0–10000) |
allocation_percent | optional | number | Allocation as a percentage (0–100, fractional ok). Friendlier alias for allocation_pct; converted to basis points server-side (e.g. 50 = 5000 bp). If both are set, allocation_percent wins. (0–100) |
reserved_headroom | optional | integer | Basis points of this experiment's split kept empty (0–10000) so a new variant can be appended into it while running without reshuffling. Group weights must sum to 10000 − reserved_headroom. Defaults to the universe's recommended_headroom when omitted. (0–10000) |
salt | optional | string | Hash salt for bucketing. Auto-generated if omitted. Immutable while running. (length 1–64) |
params | optional | object | Deprecated — the universe now owns the config schema (param_schema). Retained for back-compat; new experiments should leave this empty and declare params on the universe. Map of param-name → scalar type. (default {}) |
groups | required | object[] | Two or more variants. Weights must sum to 10000 − reserved_headroom. Existing weights are immutable while running, but a new variant may be appended into the reserved tail. |
significance_threshold | optional | 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; 0.0001–0.5) |
min_runtime_days | optional | integer | Minimum days the experiment must run before results are considered conclusive. (default 0; 0–365) |
min_sample_size | optional | integer | Minimum exposures per group before results are considered conclusive. (default 100; 1–9007199254740991) |
sequential_testing | optional | boolean | Enable sequential testing (always-valid p-values). Requires Premium plan or higher. (default false) |
goal_metric | optional | object | Inline metric — a DSL query, or an event (+ aggregation/value) the server compiles into one. |
goal_metric.name | optional | string | Stable metric key. Single segment or folder.name; lowercase letters, digits, _/-; max 128 chars. (length 0–128; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$) |
goal_metric.query | optional | string | Metric DSL string. Provide this OR event. (length 1–4096) |
goal_metric.event | optional | string | Event name to build the metric from server-side. Auto-created if missing. (length 1–256) |
goal_metric.aggregation | optional | "count_users" | "count_events" | "retention_7d" | "retention_30d" | "sum" | "avg" | Reducer for the event form. Defaults to count_users. |
goal_metric.value | optional | string | Numeric event property for sum/avg (with event). (length 1–256) |
goal_metric.min_effect_of_interest | optional | any | Per-experiment override of the metric's default minimum effect of interest (relative, 0–1) — the smallest change worth acting on for this experiment's decision. null/omitted inherits the metric default. For a guardrail, the non-inferiority margin. (default null) |
guardrail_metrics | optional | object[] | Up to 10 guardrail metrics defined inline. Each is upserted (event + metric) and attached with role=guardrail. (default []) |
listToken | optional | string | REQUIRED. The listToken returned by the most recent release_experiments_list call. It proves you listed existing release experiments and confirmed this one doesn't already exist before creating it. Call release_experiments_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).PLAN_REQUIRED— The requested feature requires a higher plan tier (e.g. sequential testing, custom alpha, holdout, group count).ALREADY_EXISTS— A resource with this name already exists in the project.GROUPS_WEIGHT_SUM— Experiment group weights must sum to 10000 (basis points).REFERENCED_NOT_FOUND— A referenced entity (universe, metric, gate, event) does not exist.VALIDATION— The request body failed structural (schema) validation.
release_experiments_get
Get one experiment
Returns the full experiment row including groups, params, allocation, and lifecycle timestamps.
Fetch one experiment to render the detail page or to inspect its current allocation and group weights.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_experiments_list
List experiments
Returns a single page of non-archived experiments ordered by updated_at desc, id desc. Use the cursor query parameter to paginate.
Snapshot 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
| Parameter | Type | Description | |
|---|---|---|---|
limit | optional | integer | Page size (1–500). Defaults to 100. (default 100; 1–500) |
cursor | optional | string | Opaque cursor returned in the previous page's next_cursor. Omit for the first page. |
status | optional | string | Filter by lifecycle status. Pass archived to return the archive tab; any other value (or omitting it) returns the non-archived experiments. |
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
release_experiments_readout_create
Mint a readout snapshot
Freezes the current results view into an immutable, dated readout snapshot — verdict, headline, per-metric numbers, the caveat list with its acknowledgment state, enrollment, and a hash of the assignment-relevant config. Ship/stop flows mint one automatically; "Share readout" mints one on demand. Snapshots are never updated after insert.
Pass requireAllAcknowledged: true to enforce ship gating server-side — returns 422 while any open caveat is not listed in acknowledgedCaveatIds.
Capture "what the data said when we decided" before shipping or stopping, so the decision stays auditable even after results move.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
kind | required | "manual" | "ship" | "stop" | Why the snapshot is being minted — manual ("Share readout"), or automatically on ship / stop. |
acknowledgedCaveatIds | optional | string[] | Ids of the open caveats the caller ticked (decision-gating acknowledgment). Unlisted caveats are stored as unacknowledged. |
requireAllAcknowledged | optional | boolean | When true, refuse (422) to mint while any open caveat is not listed in acknowledgedCaveatIds — server-side ship gating. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_experiments_readout_get
Get a readout snapshot
Returns one immutable readout snapshot — the frozen results view (verdict, headline, per-metric numbers, caveats, enrollment) captured when it was minted, plus the configHash that tells you whether it is still comparable to the live view.
Render a shared, dated readout exactly as it looked at decision time.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
readoutId | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_experiments_reanalyze
Re-queue analysis
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.
Force-refresh results after wiring up a new metric without waiting for the next nightly cron tick.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
release_experiments_restore
Restore an archived experiment (→ draft)
Drives the experiment lifecycle. Allowed transitions:
draft → running— starts allocation. Bumps thestartedAttimestamp.running → stopped— halts allocation. Existing exposures stay in the dataset.stopped → archived— soft-delete.draft → archived— discard an unstarted experiment.archived → draft— restore a soft-deleted experiment so it can be re-completed and started. Allowed only if it never started; one that already ran must be cloned instead.
Restarting an archived experiment directly is not allowed — restore it to draft first. Returns 409 on illegal transitions and 429 if the plan's experiments_running limit is exceeded on → running.
- Start —
{ "status": "running" }after wiring up the SDK and verifying targeting on staging. - Stop —
{ "status": "stopped" }once the experiment hits itsmin_runtime_daysand conclusive results land. - Archive —
{ "status": "archived" }to soft-delete after sign-off.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.INVALID_TRANSITION— The requested lifecycle transition is not allowed from the current state.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.EXPERIMENT_NO_GOAL_METRIC— The experiment has no goal metric set, which the requested action requires.EXPERIMENT_ARCHIVED_RESTART— An archived experiment cannot be restarted.EXPERIMENT_NOT_RUNNING— The action requires the experiment to be running.EXPERIMENT_RUNNING_ARCHIVE— A running experiment cannot be archived — stop it first.EXPERIMENT_RESTORE_INVALID— The experiment cannot be restored from its current state.
release_experiments_results
Get analysis results
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.
Render the results table on the experiment detail page or drive an automated decision once a goal metric reaches significance.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_experiments_set_metrics
Attach metrics
Replaces the experiment's metric attachments wholesale. Each entry pairs an existing metric_id with a role (goal / guardrail / secondary).
Returns 422 if any metric_id doesn't exist in the project. Pass { metrics: [] } to detach everything.
- Standard setup — one
goal, one or twoguardrail, optionalsecondarymetrics for diagnostics. - Detach all — send
{ "metrics": [] }before archiving.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
metrics | required | object[] | Replacement metrics list — replaces the current attachments wholesale. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.EVENT_PENDING— The referenced event is still pending review and cannot back a metric yet.REFERENCED_NOT_FOUND— A referenced entity (universe, metric, gate, event) does not exist.VALIDATION— The request body failed structural (schema) validation.METRIC_UNKNOWN_ID— The supplied metric id is malformed or not recognised.
release_experiments_start
Start an experiment (draft → running)
Drives the experiment lifecycle. Allowed transitions:
draft → running— starts allocation. Bumps thestartedAttimestamp.running → stopped— halts allocation. Existing exposures stay in the dataset.stopped → archived— soft-delete.draft → archived— discard an unstarted experiment.archived → draft— restore a soft-deleted experiment so it can be re-completed and started. Allowed only if it never started; one that already ran must be cloned instead.
Restarting an archived experiment directly is not allowed — restore it to draft first. Returns 409 on illegal transitions and 429 if the plan's experiments_running limit is exceeded on → running.
- Start —
{ "status": "running" }after wiring up the SDK and verifying targeting on staging. - Stop —
{ "status": "stopped" }once the experiment hits itsmin_runtime_daysand conclusive results land. - Archive —
{ "status": "archived" }to soft-delete after sign-off.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.INVALID_TRANSITION— The requested lifecycle transition is not allowed from the current state.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.EXPERIMENT_NO_GOAL_METRIC— The experiment has no goal metric set, which the requested action requires.EXPERIMENT_ARCHIVED_RESTART— An archived experiment cannot be restarted.EXPERIMENT_NOT_RUNNING— The action requires the experiment to be running.EXPERIMENT_RUNNING_ARCHIVE— A running experiment cannot be archived — stop it first.EXPERIMENT_RESTORE_INVALID— The experiment cannot be restored from its current state.
release_experiments_stop
Stop a running experiment
Drives the experiment lifecycle. Allowed transitions:
draft → running— starts allocation. Bumps thestartedAttimestamp.running → stopped— halts allocation. Existing exposures stay in the dataset.stopped → archived— soft-delete.draft → archived— discard an unstarted experiment.archived → draft— restore a soft-deleted experiment so it can be re-completed and started. Allowed only if it never started; one that already ran must be cloned instead.
Restarting an archived experiment directly is not allowed — restore it to draft first. Returns 409 on illegal transitions and 429 if the plan's experiments_running limit is exceeded on → running.
- Start —
{ "status": "running" }after wiring up the SDK and verifying targeting on staging. - Stop —
{ "status": "stopped" }once the experiment hits itsmin_runtime_daysand conclusive results land. - Archive —
{ "status": "archived" }to soft-delete after sign-off.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.INVALID_TRANSITION— The requested lifecycle transition is not allowed from the current state.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.EXPERIMENT_NO_GOAL_METRIC— The experiment has no goal metric set, which the requested action requires.EXPERIMENT_ARCHIVED_RESTART— An archived experiment cannot be restarted.EXPERIMENT_NOT_RUNNING— The action requires the experiment to be running.EXPERIMENT_RUNNING_ARCHIVE— A running experiment cannot be archived — stop it first.EXPERIMENT_RESTORE_INVALID— The experiment cannot be restored from its current state.
release_experiments_timeseries
Get analysis timeseries
Same row shape as /results, but returns every daily slice rather than the latest. Filter to a single metric with the metric query parameter.
Drive a chart of metric movement over the experiment runtime, or sanity-check the lift is monotonic before deciding.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
metric | optional | string | Optional metric name to filter the series. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
release_experiments_update
Update an experiment
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.
- Update metadata —
description,tag,targeting_gateeditable any time. - Ramp before launch — set
allocation_pctwhile still indraft. - Tighten significance —
significance_threshold(Pro+). - Rewire groups — replace
groupswholesale while indraft; immutable once running.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
name | optional | string | Stable experiment key. Single segment or folder.name (a-z, 0-9, _/-; max 128 chars). Used by SDKs as Shipeasy.getExperiment(user, '<name>'). Immutable after create. (length 0–128; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$) |
description | optional | any | — |
hypothesis | optional | any | — |
tag | optional | any | — |
owner_email | optional | any | — |
audience | optional | any | — |
bucket_by | optional | any | — |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
targeting_gate | optional | any | — |
holdout_gate | optional | any | Per-experiment holdout gate — the name of a holdout-type flag, or null to clear. A caller the flag passes is held out. |
allocation_pct | optional | integer | Basis-points allocation (0–10000). Use allocation_percent (0–100) for percent. Immutable while the experiment is running. (0–10000) |
reserved_headroom | optional | integer | Basis points of the split kept empty for appended variants. Group weights must sum to 10000 − reserved_headroom. May be shrunk (never grown into existing weights) while running when appending a variant. (0–10000) |
allocation_percent | optional | number | Allocation as a percentage (0–100). Friendlier alias for allocation_pct; converted to basis points server-side. Wins over allocation_pct if both are supplied. Immutable while running. (0–100) |
salt | optional | string | Hash salt. Immutable while running. (length 1–64) |
universe | optional | string | New universe name. Immutable while running. Returns 422 if the universe doesn't exist. |
params | optional | object | Deprecated — the universe owns the config schema (param_schema). Retained for back-compat. Map of param-name → scalar type. |
groups | optional | object[] | Replacement groups. Weights must sum to 10000 − reserved_headroom. Existing weights/values are immutable while running; a new variant may be appended into the reserved tail. |
significance_threshold | optional | number | — (0.0001–0.5) |
min_runtime_days | optional | integer | — (0–365) |
min_sample_size | optional | integer | — (1–9007199254740991) |
sequential_testing | optional | boolean | — |
goal_metric | optional | object | Inline metric — a DSL query, or an event (+ aggregation/value) the server compiles into one. |
goal_metric.name | optional | string | Stable metric key. Single segment or folder.name; lowercase letters, digits, _/-; max 128 chars. (length 0–128; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$) |
goal_metric.query | optional | string | Metric DSL string. Provide this OR event. (length 1–4096) |
goal_metric.event | optional | string | Event name to build the metric from server-side. Auto-created if missing. (length 1–256) |
goal_metric.aggregation | optional | "count_users" | "count_events" | "retention_7d" | "retention_30d" | "sum" | "avg" | Reducer for the event form. Defaults to count_users. |
goal_metric.value | optional | string | Numeric event property for sum/avg (with event). (length 1–256) |
goal_metric.min_effect_of_interest | optional | any | Per-experiment override of the metric's default minimum effect of interest (relative, 0–1) — the smallest change worth acting on for this experiment's decision. null/omitted inherits the metric default. For a guardrail, the non-inferiority margin. (default null) |
guardrail_metrics | optional | object[] | Replaces the guardrail set wholesale (event auto-upserted per entry). |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).PLAN_REQUIRED— The requested feature requires a higher plan tier (e.g. sequential testing, custom alpha, holdout, group count).NOT_FOUND— The resource does not exist or is not visible to the caller.IMMUTABLE_FIELD— A field that is immutable in the current state was modified (e.g. editing allocation while running).INVALID_TRANSITION— The requested lifecycle transition is not allowed from the current state.GROUPS_WEIGHT_SUM— Experiment group weights must sum to 10000 (basis points).REFERENCED_NOT_FOUND— A referenced entity (universe, metric, gate, event) does not exist.VALIDATION— The request body failed structural (schema) validation.EXPERIMENT_IMMUTABLE_FIELD— A field that is immutable while the experiment is running was modified.
Universes
Universes: the shared bucketing space all experiments draw from.
Identity. Each universe is keyed by a stable name (a-z, 0-9, _/-, max 64 chars). Experiments reference it via universe: '<name>'. The name is immutable.
Unit of randomisation. unit_type selects the attribute hashed into a 0–9999 bucket — default user_id for per-user randomisation, account_id to keep a whole account in the same group.
Holdout. holdout_range is an inclusive [lo, hi] bucket range (0–9999) reserved for measurement — callers hashed into the holdout are excluded from every experiment in the universe. Pro plan or higher.
Deletion. Blocked while any non-archived experiment references the universe — archive those first.
release_experiments_universes_archive
Delete a universe
Soft-deletes the universe. Returns 409 if any non-archived experiment still references it — archive those experiments first.
Tear down a universe after every experiment that used it has been archived.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.REFERENCED_IN_USE— The resource cannot be archived/deleted while another resource still references it.
release_experiments_universes_create
Create a universe
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.
- Default universe —
{ "name": "primary_users" }. Per-user randomisation, no holdout. - Reserved holdout — supply
holdout_rangeto carve out a measurement slice excluded from all experiments. - Account-level —
unit_type: 'account_id'so multi-seat accounts see one consistent variant.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Stable universe key. Single segment or folder.name. Lowercase letters, digits, _ or -; max 128 chars. Immutable after create. (length 0–128; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
description | optional | any | Human-readable blurb shown in the universe picker/hovercard. (default null) |
unit_type | optional | 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 | optional | any | 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) |
recommended_headroom | optional | integer | Basis points of reserved headroom seeded into each new experiment created in this universe (0 = none). Lets variants be appended into a running experiment without reshuffling. (default 0; 0–10000) |
param_schema | optional | any | The universe-owned config schema — an ordered { name, type, default }[]. Experiments may only override values per variant, never add fields. null starts an empty schema. (default null) |
listToken | optional | string | REQUIRED. The listToken returned by the most recent release_experiments_universes_list call. It proves you listed existing release experiments universes and confirmed this one doesn't already exist before creating it. Call release_experiments_universes_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).PLAN_REQUIRED— The requested feature requires a higher plan tier (e.g. sequential testing, custom alpha, holdout, group count).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.
release_experiments_universes_list
List universes
Returns a single page of universes ordered by created_at desc, id desc. The universes table has no updated_at, so this list is keyed on creation time.
Snapshot every universe in the project — for example to audit which unit_type and holdout_range are in use before launching a new experiment.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
limit | optional | integer | Page size (1–500). Defaults to 100. (default 100; 1–500) |
cursor | optional | string | Opaque cursor returned in the previous page's next_cursor. Omit for the first page. |
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
release_experiments_universes_update
Update a universe
Partial update. Only holdout_range is mutable — name and unit_type are immutable after create.
Pass "holdout_range": null to remove an existing holdout.
- Adjust holdout — change the reserved measurement slice without recreating experiments.
- Remove holdout —
{ "holdout_range": null }.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
description | optional | any | Human-readable blurb shown in the universe picker/hovercard. |
holdout_range | optional | any | 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. |
recommended_headroom | optional | integer | Basis points of reserved headroom seeded into new experiments in this universe. (0–10000) |
param_schema | optional | any | Replace the universe config schema. Additive changes + default edits are always allowed; removing a param a running experiment overrides is rejected (deprecate-only). |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).PLAN_REQUIRED— The requested feature requires a higher plan tier (e.g. sequential testing, custom alpha, holdout, group count).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Metrics
Metrics: the event-backed queries that drive tracking dashboards and experiment success / guardrail measurement.
Definition. Each metric pins one source event (event_name), one
aggregation, and (for sum/avg/quantile) a numeric value label. The
query is expressed as the DSL string (query, e.g. sum(purchase, amount))
or its typed IR (query_ir) — supply exactly one.
Identity. Keyed by a stable name (single segment or folder.name).
Resolve endpoints accept the id or the name.
Deletion. Archive (soft-delete). Blocked while the metric is attached to a running experiment — stop those first.
metrics_archive
Archive a metric
Soft-deletes (archives) the metric. Returns 409 if it is attached to a running experiment — stop those experiments first.
Retire a metric once no running experiment depends on it (the user-facing verb is archive).
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.REFERENCED_IN_USE— The resource cannot be archived/deleted while another resource still references it.
metrics_create
Create a metric
Creates an event-backed metric. Pass the query as the DSL string (query) or
the typed IR (query_ir) — exactly one. event_name must equal the event the
query references.
Returns 409 if a metric with the same name already exists, and 422 if the
query is invalid or references an unregistered event / label.
- Track an event —
count_users(<event>)for unique-user counts. - Sum a value —
sum(<event>, <label>)for revenue / quantity metrics. - Experiment success metric — create the metric, then attach its id to an experiment.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Stable metric key. Single segment or folder.name; lowercase letters, digits, _/-; max 128 chars. (length 0–128; pattern ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
event_name | required | string | Source event the query reads from. (length 1–∞) |
query | optional | string | Metric query DSL string, e.g. sum(purchase, amount). The alternative to query_ir. Every label the query references — in filters, the value position, by (…), or without (…) — must exist as a property on the tracked event's payload; a query over a label the event never carries validates fine but returns empty results. (length 1–4096) |
winsorize_pct | optional | integer | Winsorise percentile (1–99) to clamp outliers. Defaults to 99. (default 99; 1–99) |
default_min_effect_of_interest | optional | any | Default minimum effect of interest (relative, 0–1) — the smallest change in this metric worth acting on, used as the power-planning baseline. Intrinsic to the metric; an experiment overrides it per-attachment with min_effect_of_interest when a specific decision has a different cost/risk bar. null to omit. (default null) |
direction | optional | "higher_better" | "lower_better" | "neutral" | Desired direction of movement. higher_better (default), lower_better, or neutral (guardrail). (default "higher_better") |
unit | optional | any | Display unit (e.g. ms, %, $), or null when unitless. |
query_ir | optional | object | Typed query IR — the structured alternative to the query DSL string. Exactly one of query / query_ir is supplied per metric body. |
query_ir.agg | required | any | Aggregation function applied to the source event. |
query_ir.metric | required | string | Source event name (must equal event_name). (length 1–128) |
query_ir.valueLabel | optional | string | Numeric property summed/averaged for sum/avg/quantile aggregations. (length 1–128) |
query_ir.filters | optional | object[] | Label filters on the event. (default []) |
query_ir.groupBy | optional | object | Optional group-by clause (ignored for experiment analysis). |
query_ir.groupBy.op | required | "by" | "without" | by keeps the listed labels; without drops them. |
query_ir.groupBy.labels | required | string[] | Labels to group by (max 5). |
listToken | optional | string | REQUIRED. The listToken returned by the most recent metrics_list call. It proves you listed existing metrics and confirmed this one doesn't already exist before creating it. Call metrics_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.EVENT_PENDING— The referenced event is still pending review and cannot back a metric yet.REFERENCED_NOT_FOUND— A referenced entity (universe, metric, gate, event) does not exist.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.
metrics_experiments
List experiments using a metric
Returns every experiment that attaches this metric — as goal, guardrail, or secondary — ordered with running experiments first, then by role weight (goal > guardrail > secondary).
See who depends on a metric before editing or archiving it — e.g. the metric detail panel's "used by" list.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
metrics_grammar
Print the metric query DSL grammar
Print the full metric query DSL reference — grammar, aggregation semantics, filter/group-by/ratio rules, and glossed examples — used to author metrics create --query.
Parameters
No parameters.
metrics_list
List metrics
Returns every metric in the project (not paginated) — name, folder, source event, the typed queryIr, and the rendered query.
Audit every metric defined in the project — for example to find the metric id to attach as an experiment's success metric.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
metrics_series
Get a metric's time series
Compiles the metric's typed IR into Analytics Engine SQL and returns the bucketed series over the requested window (near-real-time; ingest lag is seconds). The window bounds are epoch seconds; to must be strictly greater than from. The response echoes the SQL that produced the rows.
Returns 422 when the stored definition can't compile (e.g. a label or event has gone away — re-save the metric), and 502/503 when the analytics upstream fails or isn't configured.
Render the metric trend chart / sparkline, or pull raw bucketed values to feed an external dashboard.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
from | required | integer | Window start, epoch seconds (inclusive). (≥ 0) |
to | required | integer | Window end, epoch seconds (exclusive). Must be greater than from. (≥ 0) |
bucket | optional | integer | Bucket width in seconds (60s–86400s/1d). Defaults to 3600 (hourly). Each returned point is floor-aligned to this width. (default 3600; 60–86400) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
metrics_show
Get a metric
Fetch one metric by its id or name, including the rendered DSL query and the typed IR.
Inspect a single metric's full definition before reusing it in an experiment or alert rule.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
metrics_unarchive
Unarchive a metric
Reverses a soft-delete (archive), making the metric live again. Idempotent — unarchiving a metric that is already live succeeds with no effect.
Undo an accidental archive (the metrics list "Undo" toast calls this).
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
metrics_update
Update a metric
Update a metric's definition — folder, source event, query (query DSL or typed query_ir), winsorisation, minimum detectable effect, or direction. name is immutable. Provide at most one of query / query_ir.
Refine a metric's query or guardrail direction without recreating it.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
event_name | optional | string | Source event the query reads from. (length 1–∞) |
query | optional | string | Metric query DSL string, e.g. sum(purchase, amount). The alternative to query_ir. Every label the query references — in filters, the value position, by (…), or without (…) — must exist as a property on the tracked event's payload; a query over a label the event never carries validates fine but returns empty results. (length 1–4096) |
winsorize_pct | optional | integer | Winsorise percentile (1–99) to clamp outliers. Defaults to 99. (default 99; 1–99) |
default_min_effect_of_interest | optional | any | Default minimum effect of interest (relative, 0–1) — the smallest change in this metric worth acting on, used as the power-planning baseline. Intrinsic to the metric; an experiment overrides it per-attachment with min_effect_of_interest when a specific decision has a different cost/risk bar. null to omit. (default null) |
direction | optional | "higher_better" | "lower_better" | "neutral" | Desired direction of movement. higher_better (default), lower_better, or neutral (guardrail). (default "higher_better") |
unit | optional | any | Display unit (e.g. ms, %, $), or null when unitless. |
query_ir | optional | object | Typed query IR — the structured alternative to the query DSL string. Exactly one of query / query_ir is supplied per metric body. |
query_ir.agg | required | any | Aggregation function applied to the source event. |
query_ir.metric | required | string | Source event name (must equal event_name). (length 1–128) |
query_ir.valueLabel | optional | string | Numeric property summed/averaged for sum/avg/quantile aggregations. (length 1–128) |
query_ir.filters | optional | object[] | Label filters on the event. (default []) |
query_ir.groupBy | optional | object | Optional group-by clause (ignored for experiment analysis). |
query_ir.groupBy.op | required | "by" | "without" | by keeps the listed labels; without drops them. |
query_ir.groupBy.labels | required | string[] | Labels to group by (max 5). |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Events
Events: the catalog of event names (and their typed properties) that metric queries reference.
Auto-discovery. The SDK's /collect ingest path records any unknown event name it receives as a pending row (pending: 1) so you can review it. Metrics defined on a pending event fail until it is approved.
Approval. POST /{id}/approve promotes a pending event to usable (pending: 0), optionally declaring its folder/description/properties in the same call. Registering a brand-new event via POST that matches a pending name approves it instead of failing with a conflict.
Properties. Each event can declare typed properties (name, type of string|number|boolean, required). On update/approve the properties array replaces the full set — there is no merge.
Deletion. Soft-delete (the user-facing verb is archive). Blocked while any metric still references the event — delete those metrics first.
metrics_events_approve
Approve a pending event
Promotes a pending (auto-discovered) event to usable so metrics can query it (pending → 0).
You may optionally declare the event's folder, description, or properties in the same call — the body is the same shape as update, and may be empty.
Clear an auto-discovered event out of the pending queue so metrics defined on it start resolving.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
description | optional | string | New description for the event. |
properties | optional | object[] | Replaces the full property set (no merge). Omit to leave properties unchanged. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
metrics_events_archive
Archive an event
Soft-deletes (archives) the event. Returns 409 if any metric still references it — delete those metrics first.
Retire an event from the catalog once no metric depends on it.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.REFERENCED_IN_USE— The resource cannot be archived/deleted while another resource still references it.
metrics_events_create
Register an event
Registers a new event name and (optionally) its typed properties. Only name is required.
If the name matches an existing pending (auto-discovered) row, this approves that row instead of returning a conflict. Otherwise an already-registered name returns 409.
- Register a known event —
{ "name": "checkout_completed" }so metrics can reference it. - Declare typed properties — supply
propertiesto document the event's payload shape.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Event name. Starts with a letter, digit, or _; letters, digits, _, -, .; max 128 chars. Immutable after create — this is the handle metric queries reference. (pattern ^[a-zA-Z0-9_][a-zA-Z0-9_\-.]{0,127}$) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
description | optional | string | Optional human-readable description of the event. |
properties | optional | object[] | Typed properties declared on the event. Defaults to an empty list. (default []) |
listToken | optional | string | REQUIRED. The listToken returned by the most recent metrics_events_list call. It proves you listed existing metrics events and confirmed this one doesn't already exist before creating it. Call metrics_events_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.PLAN_LIMIT— The action would exceed a plan quota (e.g. the tier's maximum experiments, metrics, or configs). Upgrade the plan or archive an existing resource.
metrics_events_get
Get an event
Returns one event's full detail. Resolves by exact id, unique id-prefix, or exact (unique) name.
Inspect one event's declared properties and pending state by id or name.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
metrics_events_list
List events
Returns every catalogued event in the project, including pending auto-discovered names. Each row carries its own pending flag, so the unapproved queue can be filtered client-side.
Snapshot the event catalog — for example to review the pending auto-discovery queue before approving names, or to confirm which events your metrics can reference.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
metrics_events_update
Update an event
Partial update of an event's folder, description, or properties. name is immutable.
properties replaces the full set (no merge) — omit it to leave properties unchanged.
Refile an event, update its description, or redeclare its typed properties.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
folder | optional | any | Optional folder name grouping items in the dashboard. Alphanumeric, _ or - (no /). Part of the SDK lookup key (<folder>/<name>). |
description | optional | string | New description for the event. |
properties | optional | object[] | Replaces the full property set (no merge). Omit to leave properties unchanged. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Ops
Operational queue: the unified table of bug reports, feature requests, and
auto-filed error/alert tickets, all over /api/admin/ops. One create
endpoint files either user type (type: bug | feature_request); list, get,
update, and link-pr are unified across every type. Also exposes the
notify escalation bell and the read-only Slack-channels list used to
resolve alert-rule notification targets.
Handles. A queue item is addressed by its per-project number (e.g. 7)
or its full id — the API resolves either.
ops_ack
Ack an item (start a run)
Acknowledge a queue item — a person or an AI agent declaring "I'm on this
now". Opens a run: stamps who picked the item up and when, assigns them as
owner, and moves the item into the matching working status
(investigating_by_ai for an AI ack, in_progress for a human one). The
dashboard renders the open run as a live working indicator (which agent +
time since the run started).
AI ack. Pass agent with your own agent type (claude, cursor,
copilot, jules; gemini aliases jules) and, when you have one, the
run's sessionId so the dashboard can deep-link to the session. If the
project has no connected trigger connector of that type the call fails
with AGENT_NOT_CONNECTED — list the available agents with ops agents list and use one of those (or connect the agent under Settings →
Triggers).
Completion. The run closes automatically on the loop's final actions —
linking the fixing PR (link-pr), an ops-notify escalation, or a
completion status change (ready_for_qa/resolved) — and the dashboard
then shows the run result (final action, PR, duration, session link).
A repeat ack supersedes the previous open run.
Call this first when picking an item up, so the team sees who/what is working on it in real time.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
agent | optional | "claude" | "cursor" | "copilot" | "jules" | "gemini" | "jarvis" | The AI agent type acking on the item's behalf — pass your own type when you are a coding agent (Claude Code passes claude, Cursor cursor, Copilot copilot, Jules/Gemini jules). Omit entirely for a human ack by the authenticated caller. |
sessionId | optional | string | The agent-run session id (e.g. Claude's session_01…), so the dashboard can deep-link to the exact run page. Omit when the harness has no session id. (length 0–300) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.AGENT_NOT_CONNECTED— The named AI agent type has no connected trigger connector in this project — list the available agents (ops agents list/GET /api/admin/agent-profiles) and use one of those, or connect the agent under Settings → Triggers.VALIDATION— The request body failed structural (schema) validation.
ops_bug
File a bug report.
Files one queue item — a bug report or a feature request — and fires the project's connectors (GitHub issue / Slack). type selects which; only the two user-fileable types are accepted (error/alert tickets are auto-filed by the platform). Returns the new id and per-project number.
- File a bug —
{ "type": "bug", "title": "Checkout 500s on Safari", "stepsToReproduce": "…" }. - File a feature request —
{ "type": "feature_request", "title": "Dark mode", "priority": "nice_to_have" }.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
title | required | string | One-line bug title (no leading/trailing whitespace). (length 1–200; pattern ^\S(.*\S)?$) |
stepsToReproduce | optional | string | How to reproduce the bug. (default ""; length 0–8000) |
actualResult | optional | string | What actually happened. (default ""; length 0–8000) |
expectedResult | optional | string | What was expected instead. (default ""; length 0–8000) |
priority | optional | any | Initial triage priority, or null. |
status | optional | any | Initial lifecycle status; defaults to open when omitted. |
assigneeId | optional | any | The users.id of the person to assign as owner at creation, or null. |
subscribers | optional | string[] | Emails of teammates to subscribe to this item's Slack pings at creation. (default []) |
tags | optional | string[] | Tag names to attach at creation (get-or-created by name, deduped case-insensitively). (default []) |
reporterEmail | optional | any | Email of the reporter, or null. |
pageUrl | optional | any | URL of the page the bug relates to, or null. |
userAgent | optional | any | Reporter's user-agent string, or null. |
viewport | optional | any | Reporter's viewport (e.g. 1280x720), or null. |
context | optional | any | Arbitrary capture context, or null. |
notify | optional | any | Where this bug's completion notification lands. |
listToken | optional | string | REQUIRED. The listToken returned by the most recent ops_list call. It proves you listed existing ops and confirmed this one doesn't already exist before creating it. Call ops_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.
ops_create
File a queue item (bug or feature request) — pass --type.
Files one queue item — a bug report or a feature request — and fires the project's connectors (GitHub issue / Slack). type selects which; only the two user-fileable types are accepted (error/alert tickets are auto-filed by the platform). Returns the new id and per-project number.
- File a bug —
{ "type": "bug", "title": "Checkout 500s on Safari", "stepsToReproduce": "…" }. - File a feature request —
{ "type": "feature_request", "title": "Dark mode", "priority": "nice_to_have" }.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
type | required | "bug" | Discriminator — files a bug. |
title | required | string | One-line bug title (no leading/trailing whitespace). (length 1–200; pattern ^\S(.*\S)?$) |
stepsToReproduce | optional | string | How to reproduce the bug. (default ""; length 0–8000) |
actualResult | optional | string | What actually happened. (default ""; length 0–8000) |
expectedResult | optional | string | What was expected instead. (default ""; length 0–8000) |
priority | optional | any | Initial triage priority, or null. |
status | optional | any | Initial lifecycle status; defaults to open when omitted. |
assigneeId | optional | any | The users.id of the person to assign as owner at creation, or null. |
subscribers | optional | string[] | Emails of teammates to subscribe to this item's Slack pings at creation. (default []) |
tags | optional | string[] | Tag names to attach at creation (get-or-created by name, deduped case-insensitively). (default []) |
reporterEmail | optional | any | Email of the reporter, or null. |
pageUrl | optional | any | URL of the page the bug relates to, or null. |
userAgent | optional | any | Reporter's user-agent string, or null. |
viewport | optional | any | Reporter's viewport (e.g. 1280x720), or null. |
context | optional | any | Arbitrary capture context, or null. |
notify | optional | any | Where this bug's completion notification lands. |
description | optional | string | What the feature is. (default ""; length 0–8000) |
useCase | optional | string | Why it's needed / the use case. (default ""; length 0–8000) |
listToken | optional | string | REQUIRED. The listToken returned by the most recent ops_list call. It proves you listed existing ops and confirmed this one doesn't already exist before creating it. Call ops_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.
ops_feature
File a feature request.
Files one queue item — a bug report or a feature request — and fires the project's connectors (GitHub issue / Slack). type selects which; only the two user-fileable types are accepted (error/alert tickets are auto-filed by the platform). Returns the new id and per-project number.
- File a bug —
{ "type": "bug", "title": "Checkout 500s on Safari", "stepsToReproduce": "…" }. - File a feature request —
{ "type": "feature_request", "title": "Dark mode", "priority": "nice_to_have" }.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
title | required | string | One-line feature-request title (no leading/trailing whitespace). (length 1–200; pattern ^\S(.*\S)?$) |
description | optional | string | What the feature is. (default ""; length 0–8000) |
useCase | optional | string | Why it's needed / the use case. (default ""; length 0–8000) |
priority | optional | any | Initial triage priority, or null. |
status | optional | any | Initial lifecycle status; defaults to open when omitted. |
assigneeId | optional | any | The users.id of the person to assign as owner at creation, or null. |
subscribers | optional | string[] | Emails of teammates to subscribe to this item's Slack pings at creation. (default []) |
tags | optional | string[] | Tag names to attach at creation (get-or-created by name, deduped case-insensitively). (default []) |
reporterEmail | optional | any | Email of the reporter, or null. |
pageUrl | optional | any | URL of the page the request relates to, or null. |
userAgent | optional | any | Reporter's user-agent string, or null. |
context | optional | any | Arbitrary capture context, or null. |
notify | optional | any | Where this request's completion notification lands. |
listToken | optional | string | REQUIRED. The listToken returned by the most recent ops_list call. It proves you listed existing ops and confirmed this one doesn't already exist before creating it. Call ops_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.VALIDATION— The request body failed structural (schema) validation.
ops_fired_alerts_list
List fired alerts
Returns the project's FIRED alerts as a bare JSON array (no pagination envelope), ordered by createdAt desc. Defaults to the currently-firing ones (status=active); pass a status to widen to resolved/dismissed history or all.
Fired alerts are raised only by the platform — the UI's killswitch handlers plus the worker's analysis consumer and alerts cron — never filed by hand, so this surface is list + triage (via PATCH), with no create. The rules that define metric-threshold alerts live at /api/admin/alert-rules.
Snapshot what is currently firing for an on-call view or the home Alerts block, or pull status=all to audit how a noisy rule has behaved over time.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
status | optional | "active" | "resolved" | "dismissed" | "all" | Filter by lifecycle state. Defaults to active (currently firing); all returns every status. (default "active") |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
ops_fired_alerts_update
Update a fired alert
Triage writes on one fired alert — the only mutations this surface allows. All body fields are optional (at least one required); only the fields present are changed.
status— flip betweenactive/resolved/dismissed.resolvedanddismissedstampresolvedAt/dismissedAt;activere-opens and clears both. A resolved alert re-fires (as the same row, re-activated) if its condition is raised again.assigneeId— the PERSON owner (ausers.id), ornullto unassign.agent— the AGENT owner: a connected trigger connector's id, or the built-in"jarvis"(Enterprise plan only —403otherwise), ornullto clear. Person and agent halves are independent.
Returns the updated row; 404 if the alert does not exist in the project.
- Wave off a known condition —
{ "status": "dismissed" }on an alert that needs no action. - Hand it to someone —
{ "assigneeId": "…" }from the ops cockpit's Owner column.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
status | optional | "active" | "resolved" | "dismissed" | New lifecycle state. resolved / dismissed stamp their timestamp; active re-opens and clears both. |
assigneeId | optional | any | PERSON owner — a users.id, or null to clear the assignment. |
agent | optional | any | AGENT owner — a connected trigger connector's id (connectors.id), the built-in "jarvis" (Enterprise plan only — rejected with 403 otherwise), or null to clear. Stored in assigneeConnectorId or assigneeAgent depending on the value; the two are mutually exclusive. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
ops_get
Get one queue item
Fetch a single queue item by its per-project number or full id.
Inspect one item's full detail before updating its status or linking a PR.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
ops_link_pr
Link a fixing PR
Record the pull request that fixes a queue item (and clears the link with prNumber: null).
Tie the fixing PR to the item so closing the PR can flip it to ready_for_qa.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
prNumber | required | any | PR number to record on the item. null unlinks the PR. |
prUrl | optional | string | Explicit PR URL. Required for error/alert tickets (no GitHub issue to derive the URL from). (format: uri) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
ops_list
List the operational queue
Returns the unified ops queue (bugs, feature requests, errors, alerts) in work order — highest priority first, oldest first within a priority — so consumers work it top-down. Filter by type and/or status, and cap with limit. Human-gated holding states (items awaiting human sign-off in the dashboard) are never returned by all/default status.
Pull the open queue to triage — e.g. every bug still open — before working items down one by one.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
type | optional | any | Filter by item type (bug/feature_request/error/alert), or all. |
status | optional | any | Filter by lifecycle status, or all. The human-gated holding state (pending_approval) is excluded from all/default and returned only when requested as the exact status. |
limit | optional | integer | Max items to return (1–500). (1–500) |
owner | optional | string | Narrow to items owned by one person OR one agent. Matches a person by users.id, email, or display name, and an agent by connector id, display name, or kebab-case handle — e.g. owner=Claude or owner=alice@acme.dev. Case-insensitive exact match, applied over the returned page. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
ops_notify
Raise an attention notification
Raise a 'needs your attention' bell notification. Create-only and idempotent on dedupeKey — re-raising with the same key updates the one card instead of stacking duplicates. It never reads, marks read, or deletes the feed, so it is safe for restricted ops keys.
Escalate work that can't land in code (a product decision, a credential only a human has, a resource only a human may edit), deduped so repeats don't spam the bell.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
title | required | string | One-line headline of what's blocked. (length 1–200) |
summary | required | string | One sentence: why it can't be fixed in code. Renders markdown. (length 1–280) |
steps | optional | string[] | Ordered steps the human should take to unblock — self-contained (the human reads only this card, not the agent's transcript), 3–6 steps, each naming the exact file, command, env var, or dashboard page. Renders markdown. |
href | optional | any | Dashboard-relative deep link to the related item. null is accepted and treated as "no link". |
dedupeKey | optional | string | Stable per-escalation key (e.g. feedback:7) so re-runs dedupe to one row. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).VALIDATION— The request body failed structural (schema) validation.
ops_update
Update a queue item
Update a queue item. The body is validated against the item's stored type: a bug accepts its content fields (title, steps-to-reproduce, actual/expected result) plus status/priority/notify and a GitHub PR link; a feature_request its content (title, description, use-case) plus the same triage fields; error/alert/measure_plan accept status/priority/notify only (their content is platform-owned). Pass at least one field.
Completing an error ticket (status resolved or ready_for_qa) also resolves the tracked error it links to; the error reopens automatically if it recurs — so completing is safe pre-deploy.
- Start working an item —
{ "status": "in_progress" }. - Hand off for review —
{ "status": "ready_for_qa" }once the fix landed (the mode PR-based loops use). - Triage —
{ "priority": "high" }, content edits on bug/feature items.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
title | optional | string | New bug title (no leading/trailing whitespace). (length 1–200; pattern ^\S(.*\S)?$) |
stepsToReproduce | optional | string | Updated reproduction steps. (length 0–8000) |
actualResult | optional | string | Updated actual result. (length 0–8000) |
expectedResult | optional | string | Updated expected result. (length 0–8000) |
status | optional | "open" | "pending_approval" | "investigating_by_ai" | "in_progress" | "blocked" | "ready_for_qa" | "resolved" | "wont_fix" | Lifecycle status of a queue item. The working flow is open → in_progress → ready_for_qa → resolved (or wont_fix, terminal from any earlier stage). blocked marks an item that can't progress until an external dependency clears — a working state a human sets and clears. ready_for_qa is what a developer sets once a fix lands; resolved is the QA sign-off, normally flipped in the dashboard after verification — set it directly from code only when the fix has been verified end-to-end. investigating_by_ai is a system-owned display state — set when the AI agent (Jarvis) picks an item up to investigate, never chosen by a human — so it is shown but not offered as a manual choice. pending_approval is the one human-gated holding state: it parks an item OUT of the work queue until a human promotes it to open in the dashboard, so GET /api/admin/ops excludes it under status=all/default and returns it only when requested as an exact status. It covers untriaged inbound that must never be auto-implemented — connector requests filed from a customer's connectors panel, and questions funnelled in from the "Stuck in onboarding?" assistant — where approving means flipping the status to open. Two earlier values were removed in favour of this single gate: triage (the onboarding-help bucket, now pending_approval) and triaged (a redundant "looked at but not started" step, now plain open). |
priority | optional | any | Triage priority, or null when not set (in an update, null clears it). |
githubPrNumber | optional | any | Link (or, when null, unlink) a GitHub pull request to this bug. |
notify | optional | any | Where this item's completion notification lands, or null. |
description | optional | string | Updated description. (length 0–8000) |
useCase | optional | string | Updated use case. (length 0–8000) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Alerts
Alert rules: the metric-threshold definitions the analysis cron evaluates each run.
What fires. Each rule binds a metricId, a comparator (gt/gte/lt/lte), and a threshold. On every cron pass the cron aggregates the metric over the trailing windowHours and raises an alert at severity when value comparator threshold holds.
Immutable metric. The bound metric (and its aggregation) is fixed at create time — there is no update path for metricId. Tune threshold/comparator/windowHours/severity/name/enabled instead, or delete + recreate to repoint the rule at a different metric.
Delivery. notify optionally targets a Slack channel and/or email for this rule; null falls back to the project's default notification settings. Slack targets require a connected Slack connector.
ops_alerts_archive
Delete an alert rule
Deletes the alert rule. The cron stops evaluating it immediately. Use this (then create a new rule) to repoint alerting at a different metric, since metricId is immutable.
Remove an alert rule that is no longer needed, or as the first half of repointing a rule at a different metric.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
ops_alerts_channels
List Slack channels
List the project's connected Slack channels — used to resolve an alert rule's notification target.
Populate a channel picker, or validate an alert rule's --slack-channel before saving.
Parameters
No parameters.
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
ops_alerts_create
Create an alert rule
Creates a metric-threshold alert rule. name, metricId, comparator, and threshold are required; windowHours defaults to 24, severity to warn, and enabled to true.
Returns 404 if metricId does not resolve, and 400 for a metric with no scalar form over a window (e.g. retention metrics) — the cron can't evaluate those.
- Threshold alert — warn when an error/latency metric crosses a value over a rolling window.
- Routed alert — set
notifyto page a specific Slack channel or on-call email instead of the project default.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Human label for the rule, shown on the alert and the rules list. (length 1–120) |
metricId | required | string | Id of the metric to evaluate. (length 1–∞) |
comparator | required | "gt" | "gte" | "lt" | "lte" | How the metric value is compared to the threshold (gt/gte/lt/lte). |
threshold | required | number | Threshold the metric value is compared against. |
windowHours | optional | integer | Lookback window (hours) the metric is aggregated over. 1–720. (default 24; 1–720) |
severity | optional | "danger" | "warn" | "info" | Severity of the raised alert. (default "warn") |
enabled | optional | boolean | Whether the rule is evaluated by the cron. (default true) |
notify | optional | any | Delivery target for a notification; null = use the project default. |
listToken | optional | string | REQUIRED. The listToken returned by the most recent ops_alerts_list call. It proves you listed existing ops alerts and confirmed this one doesn't already exist before creating it. Call ops_alerts_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).ALREADY_EXISTS— A resource with this name already exists in the project.METRIC_NOT_FOUND— The referenced metric does not exist or is not visible to the caller.REFERENCED_NOT_FOUND— A referenced entity (universe, metric, gate, event) does not exist.VALIDATION— The request body failed structural (schema) validation.
ops_alerts_list
List alert rules
Returns every alert rule in the project (not paginated). Each rule carries its bound metricId, the denormalised metricName (or null if the metric was removed), the comparator/threshold/window, severity, enabled flag, and delivery target.
Audit which metrics have alerting configured — for example to confirm an on-call threshold is set before a launch.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
q | optional | string | Case-insensitive substring filter across the resource's human-readable text columns (e.g. name, title, description). OR-matched across those columns; omit to return everything. (length 0–100) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
ops_alerts_update
Update an alert rule
Partial update of a rule's tunable knobs. metricId is immutable — the metric also pins the aggregation, so a body carrying metricId is rejected with 409 IMMUTABLE_FIELD; create a new rule bound to the other metric instead (rule deletion is dashboard-only).
Pass "notify": null to revert the rule's delivery target back to the project default.
- Tune sensitivity — change
threshold/comparator/windowHoursas the metric's baseline shifts. - Pause without losing config —
{ "enabled": false }instead of deleting the rule.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
name | optional | string | — (length 1–120) |
comparator | optional | "gt" | "gte" | "lt" | "lte" | — |
threshold | optional | number | — |
windowHours | optional | integer | — (1–720) |
severity | optional | "danger" | "warn" | "info" | — |
enabled | optional | boolean | — |
notify | optional | any | Delivery target for a notification; null = use the project default. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.IMMUTABLE_FIELD— A field that is immutable in the current state was modified (e.g. editing allocation while running).VALIDATION— The request body failed structural (schema) validation.
Agents
Connected AI agents — one per authenticated trigger connector (Claude /
Cursor / Copilot / Jules). The read-only roster behind agent assignment
and the ops ack agent types: an AI ack (ops ack <handle> --agent <type>) requires the type to appear here, so this list is where an
AGENT_NOT_CONNECTED error sends you.
ops_agents_list
List connected AI agents
The project's connected AI agents — one per authenticated trigger
connector (Claude / Cursor / Copilot / Jules). These are the agent types
ops ack accepts and the agents a queue item can be assigned to.
Discover which agent values an AI ack can use, e.g. after
an AGENT_NOT_CONNECTED error.
Parameters
No parameters.
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
Comments
Comments on a queue item — the discussion thread that hangs off any bug,
feature request, or auto-filed error/alert ticket. Append a comment or read
the thread; one level of threaded replies via parentId.
Mentions. @teammate in a body raises an in-app notification for that
person; @shipeasy asks Jarvis (the AI agent) to read the item and reply.
Comments authored by Jarvis carry authorType: system.
ops_comments_create
Comment on an item
Append a comment to a queue item's thread. The body is markdown (mentions
like @teammate notify that person; @shipeasy asks Jarvis, the AI agent,
to reply). Pass parentId to reply under an existing top-level comment
(one level of threading — a reply to a reply attaches to the same parent).
Create-only and append-only, so it is safe for restricted ops keys — the same channel the ops loop and Jarvis use to leave a note on an item.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
body | required | string | The comment body as markdown. Mentions (@teammate, @shipeasy) are parsed from it. (length 1–10000) |
parentId | optional | any | Reply under this top-level comment. Omit / null for a top-level comment. Replying to a reply attaches to the same top-level parent (threading is one level deep). |
listToken | optional | string | REQUIRED. The listToken returned by the most recent ops_comments_list call. It proves you listed existing ops comments and confirmed this one doesn't already exist before creating it. Call ops_comments_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
ops_comments_list
List an item's comments
List the comment thread on a queue item, oldest first. Each comment
carries its author (a teammate email, or system for a comment authored by
Jarvis — the AI agent), its markdown body, and parentId for the single
level of threaded replies. Removed comments are omitted.
Read the discussion on an item before replying or acting on it.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
Investigations
Investigation records on a queue item — the structured, read-only write-ups
an AI agent produces while working it (findings / a blocking question / QA
notes), plus the working run rows an ack or an AI hand-off opens. This is
the AI-write seam the cockpit's detail panel renders: list reads what a
previous run found, create appends a new record, and update fills in the
working run record you were handed (findings, PR, confidence) as you work.
ops_investigations_create
Record an investigation
Append one structured investigation record to a queue item — the AI-write
seam the cockpit's detail panel renders read-only. Post your findings
(kind: investigated), a blocking question for the team (kind: question), or how to verify the fix (kind: ready_for_qa with
qaNotes). Append-only and create-only, so it is safe for restricted ops
keys.
After working an item, leave a findings write-up (summary, markdown findings, sources inspected, confidence) so the team — and the next agent run — sees what you learned.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
kind | required | "investigated" | "detected" | "question" | "ready_for_qa" | "working" | "note" | Which lifecycle stage the record documents. |
summary | optional | string | One-line summary of the record. (length 0–2000) |
findings | optional | string | The full findings write-up (markdown). (length 0–50000) |
question | optional | string | A blocking question for the team (markdown). (length 0–10000) |
qaNotes | optional | string | How to verify the fix — QA notes (markdown). (length 0–50000) |
agent | optional | "jarvis" | "claude" | "cursor" | "copilot" | "jules" | The agent type producing the record — pass your own type when you are a coding agent. |
model | optional | string | The model the agent ran on. (length 0–200) |
connectorId | optional | string | The trigger-connector row id the agent ran through. (length 0–200) |
prNumber | optional | integer | A PR the record references. |
prUrl | optional | string | HTML URL of that PR. (length 0–2000; format: uri) |
sources | optional | object[] | The files/links inspected. |
confidence | optional | "low" | "medium" | "high" | Self-reported confidence in the record. |
tokensUsed | optional | integer | Tokens the run consumed. |
durationMs | optional | integer | Run duration in milliseconds. |
visibility | optional | "draft" | "published" | Record visibility. Defaults to published; draft keeps it out of the panel. |
startedAt | optional | string | ISO-8601 timestamp the work started. |
completedAt | optional | string | ISO-8601 timestamp the work finished. |
sessionId | optional | string | The agent-run session id, so the dashboard can deep-link to the run. (length 0–300) |
listToken | optional | string | REQUIRED. The listToken returned by the most recent ops_investigations_list call. It proves you listed existing ops investigations and confirmed this one doesn't already exist before creating it. Call ops_investigations_list first if you don't have a fresh token. |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
ops_investigations_list
List an item's investigation records
The structured, read-only investigation records on a queue item — the
findings / blocking questions / QA notes an AI agent posted while working
it, plus its working run rows. Returns published records only, newest
first (max 50).
Read what a previous agent run already found before starting your own investigation of the item.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
ops_investigations_update
Update an investigation record
Update one existing investigation record in place — the write-back seam for
the working run record you were handed when a run was launched. Fill in
the summary/findings, attach the fixing PR, record your confidence
and the sources you inspected, or flip its kind off working once the
investigation is done. A partial patch: send only the fields you want to
change. Safe for restricted ops keys (it never reads or deletes).
A run started with an empty working record; as you work,
PATCH it with your findings so the cockpit's detail panel fills in live —
no need to append a second record.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
handle | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
investigationId | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
kind | optional | "investigated" | "detected" | "question" | "ready_for_qa" | "working" | "note" | Reclassify the record's lifecycle stage (e.g. flip a working run into investigated once findings land). |
summary | optional | string | One-line summary of the record. (length 0–2000) |
findings | optional | string | The full findings write-up (markdown). (length 0–50000) |
question | optional | string | A blocking question for the team (markdown). (length 0–10000) |
qaNotes | optional | string | How to verify the fix — QA notes (markdown). (length 0–50000) |
model | optional | string | The model the agent ran on. (length 0–200) |
prNumber | optional | integer | A PR the record references. |
prUrl | optional | string | HTML URL of that PR. (length 0–2000; format: uri) |
sources | optional | object[] | The files/links inspected. |
confidence | optional | "low" | "medium" | "high" | Self-reported confidence in the record. |
tokensUsed | optional | integer | Tokens the run consumed. |
durationMs | optional | integer | Run duration in milliseconds. |
visibility | optional | "draft" | "published" | Record visibility. draft keeps it out of the panel; published surfaces it. |
completedAt | optional | string | ISO-8601 timestamp the work finished. Set it (or flip kind off working) to mark a run record done. |
sessionId | optional | string | The agent-run session id, so the dashboard can deep-link to the run. (length 0–300) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
Trigger
Recurring coding-agent triggers: the scheduled, unattended runs that burn
down the ops queue in --pr mode (one PR per fixed item; nothing
auto-merges). Shipeasy can fire four providers directly — Claude routines,
Cursor cloud agents, Copilot cloud agents, and Google Jules (the Gemini
path) — registered here as trigger connectors (idempotent per provider
key). Other platforms (Codex, Windsurf, Cline, OpenClaw, OpenCode,
Continue) schedule on their own surface — typically a GitHub Actions
schedule: cron running the platform's headless CLI with the shared
trigger prompt.
ops_trigger_create_claude
Register a Claude Code scheduled routine as the trigger connector. Creates (or idempotently updates) a coding-agent trigger connector — the recurring, unattended run that burns down the ops queue in --pr mode. Discriminated on provider; only the four Shipeasy-fireable providers are accepted (claude_trigger, cursor_trigger, `copilo…
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | optional | string | Human-readable connector label. (default "Claude trigger"; length 1–80) |
events | optional | "bug.created" | "feature_request.created"[] | Events that auto-fire the routine. Defaults to empty so the trigger does not auto-fire paid runs until events are subscribed. (default []) |
config | required | object | Non-secret config for a Claude trigger. |
config.routineId | required | string | The Claude Code routine id this connector fires (the id recorded at setup). Idempotency key for the connector. (length 1–∞) |
config.fireText | optional | string | Optional default prompt sent on a manual fire / when no event text applies. (length 1–∞) |
token | optional | string | The routine's fire bearer token (secret). Optional — a tokenless trigger is recorded but not fireable until a token is added later. Encrypted into the credentials cipher; never persisted in config or returned. (length 1–∞) |
enabled | optional | boolean | Whether the trigger is active on create. (default true) |
ops_trigger_create_copilot
Register a GitHub Copilot cloud-agent trigger. Creates (or idempotently updates) a coding-agent trigger connector — the recurring, unattended run that burns down the ops queue in --pr mode. Discriminated on provider; only the four Shipeasy-fireable providers are accepted (claude_trigger, cursor_trigger, `copilo…
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | optional | string | Human-readable connector label. (default "Copilot trigger"; length 1–80) |
events | optional | "bug.created" | "feature_request.created"[] | Events that auto-fire a Copilot agent task. Defaults to empty. (default []) |
config | required | object | Non-secret config for a Copilot trigger. |
config.owner | required | string | GitHub repo owner. Together with repo forms the connector's idempotency key (owner/repo). (length 1–∞) |
config.repo | required | string | GitHub repo name. (length 1–∞) |
config.baseRef | optional | string | Optional base ref the agent branches from. (length 1–∞) |
config.projectId | required | string | Shipeasy project id the run targets. (length 1–∞) |
token | required | string | Copilot-licensed user PAT (secret). The ops key lives in the repo's GitHub "Agents" secret store and is never sent through Shipeasy. Encrypted; never returned. (length 1–∞) |
enabled | optional | boolean | Whether the trigger is active on create. (default true) |
ops_trigger_create_cursor
Register a Cursor cloud-agent trigger (cold-fire; Shipeasy launches the run). Creates (or idempotently updates) a coding-agent trigger connector — the recurring, unattended run that burns down the ops queue in --pr mode. Discriminated on provider; only the four Shipeasy-fireable providers are accepted (claude_trigger, cursor_trigger, `copilo…
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | optional | string | Human-readable connector label. (default "Cursor trigger"; length 1–80) |
events | optional | "bug.created" | "feature_request.created"[] | Events that auto-fire a cold cloud-agent run. Defaults to empty. (default []) |
config | required | object | Non-secret config for a Cursor trigger. |
config.repoUrl | required | string | Repo the cloud agent runs against, e.g. https://github.com/owner/repo. Idempotency key for the connector. (format: uri) |
config.startingRef | optional | string | Optional git ref the run starts from. (length 1–∞) |
config.projectId | required | string | Shipeasy project id the run targets. (length 1–∞) |
apiKey | required | string | Cursor API key that launches the run (secret). Encrypted into the credentials cipher; never returned. (length 1–∞) |
opsKey | required | string | Restricted Shipeasy ops key, injected into the run as SHIPEASY_CLI_TOKEN via the launch envVars (secret). Encrypted; never returned. (length 1–∞) |
enabled | optional | boolean | Whether the trigger is active on create. (default true) |
ops_trigger_create_jules
Register a Google Jules (Gemini) trigger. Creates (or idempotently updates) a coding-agent trigger connector — the recurring, unattended run that burns down the ops queue in --pr mode. Discriminated on provider; only the four Shipeasy-fireable providers are accepted (claude_trigger, cursor_trigger, `copilo…
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | optional | string | Human-readable connector label. (default "Jules trigger"; length 1–80) |
events | optional | "bug.created" | "feature_request.created"[] | Events that auto-fire a Jules session. Defaults to empty. (default []) |
config | required | object | Non-secret config for a Jules trigger. |
config.source | required | string | Jules source for the connected repo, e.g. sources/github/owner/repo. Idempotency key for the connector. (length 1–∞) |
config.startingBranch | optional | string | Optional branch the session starts from. (length 1–∞) |
config.projectId | required | string | Shipeasy project id the run targets. (length 1–∞) |
apiKey | required | string | Jules API key that launches the session (secret). Encrypted into the credentials cipher; never returned. (length 1–∞) |
opsKey | required | string | Restricted Shipeasy ops key, embedded in the prompt (Jules exposes no env channel) (secret). Encrypted; never returned. (length 1–∞) |
enabled | optional | boolean | Whether the trigger is active on create. (default true) |
Projects
Projects: the account-level container every other resource is scoped to.
Account-level, not bound-project-level. Both operations resolve from the caller's credential rather than the .shipeasy-bound project — current reads the project the auth header maps to, and upsert find-or-creates under the session's owner. Neither touches the local .shipeasy binding; recording the result there is a consumer side-effect layered on top.
Idempotent upsert. A project is keyed by (owner_email, domain). Calling upsert again with the same domain returns the existing project with created: false, so it is safe to run on every install.
projects_current
Show the current project
Returns the project the caller's auth header resolves to — plan, status, billing, and which modules are enabled. The server reads the project from the credential, so there is no id parameter. Powers whoami.
Resolve who you are — the project, plan, and enabled modules tied to the current credential — without passing an id. Backs a registry-driven whoami.
Parameters
No parameters.
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
projects_update
Update the current project
Update the current project's settings — name, domain, slug, default environment, timezone, experiment-analysis knobs (statistical method, significance threshold, auto-rollback, minimum sample days), and the per-module enable flags. Partial: only the fields you send change.
The project id in the path must match the project the caller's credential resolves to (a credential can only edit its own project). Changing domain re-stamps the allowed origin into every live SDK key.
Rename a project, move its domain, toggle a module on/off, or tune the experiment-analysis defaults without leaving the CLI.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
name | optional | string | New project name. (length 1–120) |
domain | optional | string | Lowercase bare hostname (e.g. acme.com, app.acme.com, *.acme.com), or * to allow any origin. Full URLs with https:// are not accepted. The project is keyed by (owner_email, domain), so a second call with the same domain returns the existing project. (length 1–2048; pattern ^(\*|(\*\.)?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+)$) |
slug | optional | string | URL-safe identifier used in app URLs and SDK config. Lowercase letters, numbers, and hyphens; 2–48 chars; cannot start or end with a hyphen. The caller lowercases the raw slug before sending. (length 2–48; pattern ^[a-z0-9](?:[a-z0-9-]{0,46}[a-z0-9])?$) |
defaultEnv | optional | "dev" | "staging" | "prod" | Default environment new resources are scoped to. |
timezone | optional | string | IANA timezone the project's daily analysis runs in. (length 1–64) |
statMethod | optional | "sequential" | "fixed" | "bayesian" | Statistical method the experiment analyzer uses. |
sigThreshold | optional | "0.01" | "0.05" | "0.10" | Significance threshold (alpha) for experiment analysis. |
autoRollback | optional | boolean | Whether a failing guardrail auto-rolls back the experiment. |
minSampleDays | optional | integer | Minimum number of days an experiment must run before it can be called. (1–365) |
moduleTranslations | optional | boolean | Enable/disable the i18n/translations module. |
moduleConfigs | optional | boolean | Enable/disable the dynamic-configs module. |
moduleGates | optional | boolean | Enable/disable the feature-gates module. |
moduleExperiments | optional | boolean | Enable/disable the experiments module. |
moduleFeedback | optional | boolean | Enable/disable the feedback/ops module. |
moduleUser | optional | boolean | Enable/disable the user-management module. |
moduleEvents | optional | boolean | Enable/disable the events module. |
minSampleSize | optional | integer | Verdict power guard — minimum users per arm before a ship/hold verdict. (2–1000000) |
minRuntimeDays | optional | integer | Minimum days an experiment must run before a verdict (peeking guard). (0–365) |
defaultPower | optional | number | Target statistical power (1−β) feeding the realized-MDE calculation. (0.5–0.99) |
ciConfidence | optional | number | Confidence level for the interval surfaced on results (any value in [0.5, 0.999], e.g. 0.90, 0.95, 0.975, 0.99). (0.5–0.999) |
defaultAllocationPct | optional | integer | Default traffic allocation (basis points, 1000 = 10%) new experiments start with; overridable per experiment. (1–10000) |
defaultHoldout | optional | integer | Default holdout carve-out (basis points) that seeds each new universe's holdout (0 = none). (0–10000) |
defaultWinsorizePct | optional | integer | Default winsorization percentile new metrics start with; overridable per metric. (1–99) |
defaultMei | optional | any | Default minimum effect of interest (relative, 0–1) new metrics start with; overridable per metric and per experiment. Null clears it. |
cupedBaselineDays | optional | integer | CUPED baseline window — days of pre-experiment history, frozen at start. (1–365) |
cupedMinOverlap | optional | number | CUPED selection-bias guard — min share of users with a baseline, else skip. (0.01–0.99) |
cupedMinBaselineUsers | optional | integer | CUPED — minimum users with a baseline before it runs at all. (10–100000) |
msprtTauMeiFactor | optional | number | mSPRT prior width — τ = minimum effect of interest × this factor. (0.1–2) |
msprtTauSdFactor | optional | number | mSPRT fallback prior width — τ = this × control SD when no MEI is set. (0.05–1) |
srmThreshold | optional | number | SRM chi-square p-value below which the run is called invalid. (0.0001–0.05) |
errorAutocloseDays | optional | integer | Days an open tracked error may go unseen before the nightly sweep auto-resolves it. 0 disables auto-close for this project. (0–365) |
errorTicketMinOccurrences | optional | integer | Occurrence count a tracked error must cross before an error ticket is auto-filed into the ops queue. Requires a paid plan — the request is rejected with 403 on a plan without the ops_auto_error_issues entitlement. (1–10000) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.VALIDATION— The request body failed structural (schema) validation.
projects_upsert
Find-or-create a Shipeasy project by domain (idempotent) and bind the cwd to it via .shipeasy. Use this on fresh installs BEFORE any other write tool — every other write tool refuses to run until .shipeasy exists. Re-running with the same domain returns the existing project unchanged.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
domain | required | string | Hostname-like identifier for the project (e.g. shouks.app, acme.com). Primary key for upsert. |
name | optional | string | Human-readable project name. Defaults to the domain on first create; ignored on later upserts. |
path | optional | string | Directory to write .shipeasy in. Defaults to the MCP server's cwd. |
bind | optional | boolean | Write .shipeasy after upsert. Default true. Set false to skip binding. |
whoami
Show the current project
Returns the project the caller's auth header resolves to — plan, status, billing, and which modules are enabled. The server reads the project from the credential, so there is no id parameter. Powers whoami.
Resolve who you are — the project, plan, and enabled modules tied to the current credential — without passing an id. Backs a registry-driven whoami.
Parameters
No parameters.
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
i18n
String Manager (i18n): the worker-safe REST surface — locale profiles, the insert-only key push, single-key overwrite, profile publish, and the read-only key/draft listings.
The fs/AST parts (scan, validate, install-loader, codemod) are NOT part of this API — they stay in the fs-having CLI/MCP.
Profiles
Locale profiles (e.g. en:prod) — create, list, and publish a profile to the CDN.
i18n_profiles_create
Create an i18n profile. Create a locale profile. name is the stable handle (e.g. fr:prod).
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Profile handle to create, e.g. en:prod or fr:prod. Lowercase alphanumeric start, then letters/digits/_/:/./-; max 64 chars. The locale is encoded in the handle, so no separate locale fields are accepted. (length 1–64; pattern ^[a-z0-9][a-z0-9_:.-]*$) |
listToken | optional | string | REQUIRED. The listToken returned by the most recent i18n_profiles_list call. It proves you listed existing i18n profiles and confirmed this one doesn't already exist before creating it. Call i18n_profiles_list first if you don't have a fresh token. |
i18n_profiles_list
List i18n profiles. Returns every locale profile in the project (e.g. en:prod, fr:prod).
Parameters
No parameters.
i18n_profiles_publish
Publish a profile live. Publish a profile to the CDN — rebuild its KV snapshot + purge the edge. Publishing is PROFILE-WIDE: the whole profile is snapshotted into one KV blob, so the body takes no options.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
profileId | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Keys
Translation keys — the insert-only push, single-key overwrite, and key listing.
i18n_keys_list
List i18n keys. List keys for a profile, optionally filtered to a name prefix.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
profile_id | optional | string | Profile id to list keys for. |
prefix | optional | string | Only keys whose name starts with this. |
q | optional | string | Free-text search — matches keys whose name, value, OR description contains this substring (case-insensitive). Use it to find the key behind a piece of on-screen copy. (length 0–100) |
limit | optional | integer | Max keys to return (1–500). (1–500) |
offset | optional | integer | Number of keys to skip before returning limit rows (offset pagination). (default 0; ≥ 0) |
i18n_keys_push
Push i18n keys (insert-only, or force to overwrite). Add NEW keys to a profile. Insert-only by default — existing keys are left untouched and reported back as skipped.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
profile_id | required | string | Target profile id to add keys to. (format: uuid) |
keys | required | object[] | Keys to add. Insert-only by default — existing keys are reported back as skipped (set force to overwrite them instead). |
force | optional | boolean | Overwrite keys that already exist with the submitted value instead of skipping them. Overwritten keys come back as updated. Off by default so a routine push can never clobber live translations. (default false) |
i18n_keys_set
Set a key's value and publish it live. Upsert a single key's value into a profile and immediately publish the whole profile (KV rebuild + CDN purge) so the new value is live in one call. The key is inserted when new and overwritten when it already exists. profile is a profile name — omit it to target the project'…
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
key | required | string | Dotted key path to set, e.g. home.cta. (length 1–256) |
value | required | string | New value for the key. Inserted when the key is new, overwritten when it exists. |
profile | optional | string | Profile name to target, e.g. en:prod. Omit to target the project's default-marked profile. (length 1–64) |
description | optional | string | Optional human note to store with the key. |
i18n_keys_update
Update one i18n key. Overwrite a single existing key's value — the only overwrite path.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
value | required | string | New value for the key (the only overwrite path). |
description | optional | string | Optional human note to store with the key. |
variables | optional | string[] | Explicit {{var}} placeholder names in the value. Omit to auto-derive them from the value. |
Drafts
Machine-translation drafts awaiting review before publish.
i18n_drafts_create
Create a translation draft. Stage a new translation draft against a target profile, optionally seeding its keys from a source profile.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
name | required | string | Draft name, e.g. the target locale being staged. (length 1–64) |
profile_id | required | string | Profile the draft targets. (format: uuid) |
source_profile_id | optional | string | Optional profile to seed the draft's keys from. (format: uuid) |
listToken | optional | string | REQUIRED. The listToken returned by the most recent i18n_drafts_list call. It proves you listed existing i18n drafts and confirmed this one doesn't already exist before creating it. Call i18n_drafts_list first if you don't have a fresh token. |
i18n_drafts_list
List translation drafts. List staged translation drafts awaiting review/publish.
Parameters
No parameters.
i18n_drafts_update
Update a translation draft. Transition a draft's lifecycle state (open / merged / abandoned).
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
draftId | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
status | optional | "open" | "merged" | "abandoned" | New lifecycle state for the draft. |
Errors
Tracked production errors: the deduplicated, fingerprinted error stream the
SDK + framework error sinks feed. Read-only list/get plus a status update
(open/resolved/ignored), an auto-file-to-GitHub-issue action, and a
time-series rollup. Errors are ingestion-only — there is no create route.
errors_get
Get a tracked error
Returns a single tracked error by its id, including the latest occurrence's stack, extras, and consequence, plus occurrences — the sampled per-instance detail rows behind the issue (newest first; exhaustive while the issue is small, thinned at volume, capped at 100). Returns 404 if no such error exists in the project.
Drill into one issue — fetch its full stack and seenUrls to investigate, or walk occurrences to see how the failing message/stack varies across instances.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
NOT_FOUND— The resource does not exist or is not visible to the caller.
errors_list
List tracked errors
Returns a single page of tracked production errors as a bare JSON array (no pagination envelope), ordered by lastSeenAt desc. Filter with status, free-text-search with q, and cap the page with limit.
Tracked errors are never filed by hand — an ingestion path (worker log drain / the see() SDK reporter) folds each occurrence into a row keyed by fingerprint, bumping count and lastSeenAt. This surface only reads them and (via PATCH) flips their status.
Snapshot the project's open issues for a triage dashboard, or drive a CI gate that fails the build when any open error of kind: uncaught exists in prod.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
status | optional | "open" | "resolved" | "ignored" | "all" | Filter by triage state. all (the default) returns every status. (default "all") |
q | optional | string | Case-insensitive substring match against message, errorType, and subject. (length 0–200) |
limit | optional | integer | Maximum number of rows to return (1–500). Defaults to 200. (default 200; 1–500) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).
errors_resolve
Resolve a tracked error
Marks one tracked error resolved — the single-purpose "close out" action. Takes no body; it is PATCH /api/admin/errors/{id} pinned to { "status": "resolved" }, exposed so tooling can close an error without being handed the full open/resolved/ignored status machine. A resolved error reopens automatically (ingestion-side) if it recurs, so resolving is always safe: a premature resolve un-does itself on the next occurrence. Returns the updated row; 404 if the error does not exist.
Close out a tracked error from an agent or script once its fix has shipped — e.g. after a deploy, resolve every open issue the change addressed and let recurrence reopen anything that wasn't actually fixed.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
Errors — beyond the common errors:
NOT_FOUND— The resource does not exist or is not visible to the caller.
errors_series
Get an error's occurrence series
Returns a bucketed occurrence timeseries for one tracked error (by its fingerprint), read from the shipeasy_errors Analytics Engine dataset (near-real-time; ingest lag is seconds). The window bounds are epoch seconds; to must be strictly greater than from. The response echoes the SQL that produced the rows.
Render the trend sparkline / occurrence chart on the error detail panel, or pull the raw bucketed counts to alert when an issue's rate spikes.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
id | required | string | A resource path identifier — an opaque xxx_<ULID> id (~30 chars) or the resource's name/key. 1–128 characters; the upper bound matches the longest name/key any resource accepts, so an over-long value can never name a real row. (length 1–128) |
from | required | integer | Window start, epoch seconds (inclusive). (≥ 0) |
to | required | integer | Window end, epoch seconds (exclusive). Must be greater than from. (≥ 0) |
bucket | optional | integer | Bucket width in seconds (60s–86400s/1d). Defaults to 3600 (hourly). Each returned point is floor-aligned to this width. (default 3600; 60–86400) |
Errors — beyond the common errors:
BAD_REQUEST— Malformed request (bad JSON, missing project scope).NOT_FOUND— The resource does not exist or is not visible to the caller.
Auth
Device-flow (PKCE) authentication shared with the CLI — authenticate once and every mutating tool can write. The token is stored in ~/.config/shipeasy/config.json.
auth_check
Report whether ~/.config/shipeasy/config.json holds a valid CLI token. Returns { authenticated, project_id, base_url, user_email }.
Parameters
No parameters.
auth_login
Launch the PKCE device-auth flow via shipeasy login. Opens a browser; blocks up to 5 minutes. Caller should render a 'waiting for browser…' spinner.
Parameters
No parameters.
auth_logout
Delete ~/.config/shipeasy/config.json — the ONE session shared by the shipeasy CLI and every MCP client on this machine. No network call. This is not restorable from MCP: re-authenticating needs a browser sign-in in a terminal (shipeasy login), which this transport cannot perform, so calling this strands the current task and every other tool until a human signs in again. Do NOT call it to 'reset' or troubleshoot a failing call — a 401/403 is fixed by signing in, not by deleting the credential first. Only call it when the user explicitly asked to sign out, and pass confirm: true to acknowledge that.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
confirm | required | boolean | Must be true. Acknowledges that this deletes the machine-wide session and that only a human at a terminal can restore it. |
SDK docs
Fetch SDK documentation — feature pages, nested snippets, and installable skills — from each SDK's published GitHub Pages docs.
docs_get
Fetch one SDK doc page or snippet
Fetch one feature page (flags, experiments, …) or nested snippet (release/experiments, …), substituting declared {{placeholders}} from caller args.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
sdk | optional | "typescript" | "javascript" | "node" | "ts" | "python" | "go" | "java" | "kotlin" | "php" | "swift" | "ruby" | SDK language. Defaults to the sdk recorded in the nearest .shipeasy when omitted. |
path | required | string | Page key or snippet 'group/resource'. |
framework | optional | string | Framework hint (substitutes {{FRAMEWORK}}). |
name | optional | string | Resource name (substitutes {{RESOURCE_NAME}}). |
docs_list
List an SDK's documentation tree
Fetch an SDK's /docs/manifest.json and return the doc tree — feature pages, nested snippet groups, the optional setup-topic map, and whether an installable skill exists.
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
sdk | optional | "typescript" | "javascript" | "node" | "ts" | "python" | "go" | "java" | "kotlin" | "php" | "swift" | "ruby" | SDK language. Defaults to the sdk recorded in the nearest .shipeasy when omitted. |
docs_skill
Fetch an SDK's installable LLM skill
Fetch the SDK's skill/SKILL.md (frontmatter intact) so an agent can install it verbatim. The CLI --install writes it locally (a consumer fs side-effect).
Parameters
| Parameter | Type | Description | |
|---|---|---|---|
sdk | optional | "typescript" | "javascript" | "node" | "ts" | "python" | "go" | "java" | "kotlin" | "php" | "swift" | "ruby" | SDK language. Defaults to the sdk recorded in the nearest .shipeasy when omitted. |
install | optional | boolean | CLI only: write the skill to the local agent skills dir. |
MCP server
Hand the docs and tools to Claude Code, Cursor, Windsurf, or any MCP-compatible AI assistant — and let it do the boring setup for you.
Install in your agent
One plugin tree, every coding agent. Install Shipeasy's skills + MCP server into Claude Code, Codex, GitHub Copilot CLI, OpenCode, Cursor, Windsurf, Cline, Gemini, Continue, and more.