@shipeasy/openapi 1.6.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/README.md +37 -0
  2. package/dist/chunk-643YSMLU.js +1616 -0
  3. package/dist/chunk-643YSMLU.js.map +1 -0
  4. package/dist/chunk-MRW3DJ57.js +3385 -0
  5. package/dist/chunk-MRW3DJ57.js.map +1 -0
  6. package/dist/client-K0ShmsC7.d.ts +11284 -0
  7. package/dist/client.d.ts +1 -0
  8. package/dist/client.js +215 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/custom.d.ts +86 -0
  11. package/dist/custom.js +300 -0
  12. package/dist/custom.js.map +1 -0
  13. package/dist/index.d.ts +29 -41
  14. package/dist/index.js +258 -4375
  15. package/dist/index.js.map +1 -0
  16. package/dist/node-context.d.ts +81 -33
  17. package/dist/node-context.js +98 -44
  18. package/dist/node-context.js.map +1 -0
  19. package/dist/schemas.d.ts +7973 -0
  20. package/dist/schemas.js +1099 -0
  21. package/dist/schemas.js.map +1 -0
  22. package/openapi.json +15922 -3232
  23. package/openapi.yaml +14277 -0
  24. package/package.json +33 -26
  25. package/spec/components/errors.yaml +53 -0
  26. package/spec/components/parameters.yaml +32 -0
  27. package/spec/components/responses.yaml +122 -0
  28. package/spec/components/schemas/alert-rules.yaml +175 -0
  29. package/spec/components/schemas/attributes.yaml +157 -0
  30. package/spec/components/schemas/common.yaml +92 -0
  31. package/spec/components/schemas/configs.yaml +371 -0
  32. package/spec/components/schemas/connectors.yaml +587 -0
  33. package/spec/components/schemas/errors-api.yaml +209 -0
  34. package/spec/components/schemas/events.yaml +321 -0
  35. package/spec/components/schemas/experiments.yaml +865 -0
  36. package/spec/components/schemas/gate-templates.yaml +237 -0
  37. package/spec/components/schemas/gates.yaml +890 -0
  38. package/spec/components/schemas/i18n.yaml +478 -0
  39. package/spec/components/schemas/keys.yaml +186 -0
  40. package/spec/components/schemas/killswitches.yaml +309 -0
  41. package/spec/components/schemas/metrics.yaml +547 -0
  42. package/spec/components/schemas/ops.yaml +1013 -0
  43. package/spec/components/schemas/projects.yaml +222 -0
  44. package/spec/components/schemas/search.yaml +46 -0
  45. package/spec/components/schemas/universes.yaml +127 -0
  46. package/spec/openapi.yaml +367 -0
  47. package/spec/paths/alert-rules.yaml +258 -0
  48. package/spec/paths/attributes.yaml +272 -0
  49. package/spec/paths/configs.yaml +758 -0
  50. package/spec/paths/connectors.yaml +782 -0
  51. package/spec/paths/errors.yaml +382 -0
  52. package/spec/paths/events.yaml +380 -0
  53. package/spec/paths/experiments.yaml +803 -0
  54. package/spec/paths/gate-templates.yaml +267 -0
  55. package/spec/paths/gates.yaml +465 -0
  56. package/spec/paths/i18n.yaml +557 -0
  57. package/spec/paths/keys.yaml +182 -0
  58. package/spec/paths/killswitches.yaml +574 -0
  59. package/spec/paths/metrics.yaml +313 -0
  60. package/spec/paths/ops.yaml +446 -0
  61. package/spec/paths/projects.yaml +210 -0
  62. package/spec/paths/search.yaml +62 -0
  63. package/spec/paths/universes.yaml +255 -0
  64. package/dist/operations/attributes.d.ts +0 -33
  65. package/dist/operations/attributes.js +0 -16
  66. package/dist/operations/cli-adapter.d.ts +0 -35
  67. package/dist/operations/cli-adapter.js +0 -91
  68. package/dist/operations/coerce.d.ts +0 -32
  69. package/dist/operations/coerce.js +0 -53
  70. package/dist/operations/configs.d.ts +0 -28
  71. package/dist/operations/configs.js +0 -119
  72. package/dist/operations/docs.d.ts +0 -37
  73. package/dist/operations/docs.js +0 -39
  74. package/dist/operations/events.d.ts +0 -28
  75. package/dist/operations/events.js +0 -121
  76. package/dist/operations/experiments.d.ts +0 -28
  77. package/dist/operations/experiments.js +0 -280
  78. package/dist/operations/gates.d.ts +0 -28
  79. package/dist/operations/gates.js +0 -132
  80. package/dist/operations/i18n.d.ts +0 -28
  81. package/dist/operations/i18n.js +0 -121
  82. package/dist/operations/index.d.ts +0 -63
  83. package/dist/operations/index.js +0 -1751
  84. package/dist/operations/killswitches.d.ts +0 -28
  85. package/dist/operations/killswitches.js +0 -126
  86. package/dist/operations/mcp-adapter.d.ts +0 -35
  87. package/dist/operations/mcp-adapter.js +0 -94
  88. package/dist/operations/metrics.d.ts +0 -30
  89. package/dist/operations/metrics.js +0 -114
  90. package/dist/operations/ops.d.ts +0 -28
  91. package/dist/operations/ops.js +0 -313
  92. package/dist/operations/projects.d.ts +0 -28
  93. package/dist/operations/projects.js +0 -36
  94. package/dist/operations/sdk-docs.d.ts +0 -28
  95. package/dist/operations/sdk-docs.js +0 -160
  96. package/dist/operations/types.d.ts +0 -138
  97. package/dist/operations/types.js +0 -9
  98. package/dist/operations/universes.d.ts +0 -28
  99. package/dist/operations/universes.js +0 -93
  100. package/dist/operations/util.d.ts +0 -33
  101. package/dist/operations/util.js +0 -9
  102. package/dist/resources/alert-rules.d.ts +0 -50
  103. package/dist/resources/alert-rules.js +0 -75
  104. package/dist/resources/attributes.d.ts +0 -19
  105. package/dist/resources/attributes.js +0 -10
  106. package/dist/resources/configs.d.ts +0 -681
  107. package/dist/resources/configs.js +0 -509
  108. package/dist/resources/events.d.ts +0 -61
  109. package/dist/resources/events.js +0 -42
  110. package/dist/resources/experiments.d.ts +0 -849
  111. package/dist/resources/experiments.js +0 -707
  112. package/dist/resources/gates.d.ts +0 -808
  113. package/dist/resources/gates.js +0 -522
  114. package/dist/resources/i18n.d.ts +0 -84
  115. package/dist/resources/i18n.js +0 -60
  116. package/dist/resources/index.d.ts +0 -2767
  117. package/dist/resources/index.js +0 -2563
  118. package/dist/resources/killswitches.d.ts +0 -436
  119. package/dist/resources/killswitches.js +0 -514
  120. package/dist/resources/metrics.d.ts +0 -54
  121. package/dist/resources/metrics.js +0 -40
  122. package/dist/resources/ops.d.ts +0 -88
  123. package/dist/resources/ops.js +0 -36
  124. package/dist/resources/projects.d.ts +0 -54
  125. package/dist/resources/projects.js +0 -14
  126. package/dist/resources/universes.d.ts +0 -185
  127. package/dist/resources/universes.js +0 -234
  128. package/dist/schemas/alert-rules.d.ts +0 -65
  129. package/dist/schemas/alert-rules.js +0 -37
  130. package/dist/schemas/configs.d.ts +0 -154
  131. package/dist/schemas/configs.js +0 -134
  132. package/dist/schemas/constants.d.ts +0 -6
  133. package/dist/schemas/constants.js +0 -7
  134. package/dist/schemas/experiments.d.ts +0 -229
  135. package/dist/schemas/experiments.js +0 -221
  136. package/dist/schemas/folder.d.ts +0 -10
  137. package/dist/schemas/folder.js +0 -8
  138. package/dist/schemas/gates.d.ts +0 -386
  139. package/dist/schemas/gates.js +0 -190
  140. package/dist/schemas/index.d.ts +0 -11
  141. package/dist/schemas/index.js +0 -762
  142. package/dist/schemas/killswitches.d.ts +0 -110
  143. package/dist/schemas/killswitches.js +0 -226
  144. package/dist/schemas/metric-name.d.ts +0 -5
  145. package/dist/schemas/metric-name.js +0 -6
  146. package/dist/schemas/pagination.d.ts +0 -37
  147. package/dist/schemas/pagination.js +0 -44
  148. package/dist/schemas/universes.d.ts +0 -35
  149. package/dist/schemas/universes.js +0 -55
  150. package/dist/transport.d.ts +0 -30
  151. package/dist/transport.js +0 -44
@@ -0,0 +1,367 @@
1
+ openapi: 3.2.0
2
+ info:
3
+ title: Shipeasy Admin API
4
+ version: 2.0.0
5
+ description: |-
6
+ REST API for managing feature gates, experiments, configs, universes, and killswitches in a Shipeasy project. Authenticate with an admin SDK key (`Authorization: Bearer sdk_admin_…`) and scope every request to a project via the `X-Project-Id` header.
7
+
8
+ Mint admin keys via `POST /api/admin/keys` with `type: "admin"`. Keys expire after 90 days; rotate with the `revoke` action.
9
+ contact:
10
+ name: Shipeasy
11
+ url: https://shipeasy.ai
12
+ license:
13
+ name: Proprietary
14
+ identifier: LicenseRef-Proprietary
15
+ servers:
16
+ - url: https://shipeasy.ai
17
+ description: Production
18
+ - url: http://localhost:3000
19
+ description: Local Next.js dev server
20
+ security:
21
+ - bearerSdkKey: []
22
+ tags:
23
+ - name: Release
24
+ summary: >-
25
+ Feature delivery — flags, kill switches, dynamic configs, A/B experiments,
26
+ and the universes they bucket in.
27
+ kind: nav
28
+ description: |-
29
+ Release: the feature-delivery surface. One roof over the five resources
30
+ that decide which code path a user gets — feature gates (flags), kill
31
+ switches, dynamic configs, A/B/n experiments, and the universes that bucket
32
+ them — each exposed as its own subcommand group.
33
+
34
+ **Groups.**
35
+ - `flags` — boolean feature gates: AND-combined targeting rules + a percentage rollout (basis points), evaluated on the SDK hot path.
36
+ - `killswitch` (`ks`) — per-env boolean overrides for incident response; no rules, no rollout, versioned per environment.
37
+ - `configs` — JSON-Schema-validated structured values with a draft → publish workflow, delivered per environment.
38
+ - `experiments` — randomised A/B/n assignment plus the analysis pipeline (t-test, sequential testing, SRM detection); `universes` hold the shared bucketing space and holdouts the experiments draw from.
39
+
40
+ **Delivery model.** Every write rebuilds the project's KV blob and purges
41
+ the CDN — SDKs poll at the plan interval and never touch the database on
42
+ the hot path. The destructive verb is `archive` (soft-delete), never
43
+ `delete`.
44
+
45
+ Run `shipeasy release <group> --help` for the full contract of each group.
46
+ - name: Flags
47
+ parent: Release
48
+ description: |-
49
+ Feature gates: boolean flags evaluated at runtime against project rules + a percentage rollout.
50
+
51
+ **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.
52
+
53
+ **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:
54
+ - **Flat** — `rules` (AND-combined predicates) gate the caller, then `rollout_pct` (basis points, 0–10000) hashes them into a bucket. Used for simple `is in X% rollout` gates.
55
+ - **Gatekeeper stack** — an ordered array of `condition` and `rollout` sub-gates, evaluated top-to-bottom; first match wins. Used to express `internal-only ∪ 1% beta ∪ 50% public` in one gate. When `stack` is present it takes precedence over the flat fields.
56
+
57
+ **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`).
58
+
59
+ **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%).
60
+
61
+ **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.
62
+ - name: Killswitch
63
+ parent: Release
64
+ x-cli:
65
+ aliases:
66
+ - ks
67
+ description: |-
68
+ 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.
69
+
70
+ **Identity.** Each killswitch is keyed by `name` in `folder.name` form (e.g. `payments.checkout`). Immutable after create.
71
+
72
+ **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.
73
+
74
+ **Switches map.** Optional `switches: { key: bool }` overrides the flat `value` for specific named call sites — useful for region/feature-scoped kills.
75
+
76
+ **Versioning.** Each publish (create, update, set-switch, unset-switch) bumps the per-env `version` monotonically. SDKs deliver the latest published version.
77
+ - name: Configs
78
+ parent: Release
79
+ description: |-
80
+ Dynamic configs: JSON-Schema-validated structured values delivered to SDKs and editable per environment with a draft/publish workflow.
81
+
82
+ **Identity.** Each config is keyed by `name` in `folder.name` form (e.g. `pricing.tiers`). Immutable after create.
83
+
84
+ **Schema-first.** Every config carries a JSON Schema (draft 2020-12, top-level `type: 'object'`). Every published value is validated against it.
85
+
86
+ **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.
87
+
88
+ **Versioning.** Each publish bumps the per-env `version` monotonically. SDKs deliver the latest published version for each env.
89
+ - name: Experiments
90
+ parent: Release
91
+ description: |-
92
+ A/B/n experiments: randomised group assignment plus the analysis pipeline (t-test, sequential testing, SRM detection) on top of a universe.
93
+
94
+ **Identity.** Stable `name` (a-z, 0-9, `_`/`-`, max 64 chars). Immutable after create.
95
+
96
+ **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.
97
+
98
+ **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.
99
+
100
+ **Immutable while running.** `allocation_pct`, `groups`, `salt`, `universe`, `params` cannot be edited on a running experiment — stop it first.
101
+
102
+ **Metrics.** Attach via `POST /{id}/metrics`. Each metric has a role: `goal` drives the decision, `guardrail` blocks ship on regression, `secondary` is informational.
103
+
104
+ **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.
105
+ - name: Universes
106
+ parent: Experiments
107
+ description: |-
108
+ Universes: the shared bucketing space all experiments draw from.
109
+
110
+ **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.
111
+
112
+ **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.
113
+
114
+ **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.
115
+
116
+ **Deletion.** Blocked while any non-archived experiment references the universe — archive those first.
117
+ - name: Templates
118
+ parent: Flags
119
+ description: |-
120
+ Targeting-rule templates: reusable `{ attr, op, value }` rule definitions
121
+ (country, email-domain, region presets, …). Read-only built-ins ship with
122
+ the platform; each project can also save its own. To target by
123
+ country/plan/region, list templates, copy the matching template's `rules`,
124
+ substitute the concrete value(s), and pass them to `release flags create`.
125
+ - name: Attributes
126
+ parent: Flags
127
+ description: |-
128
+ Targeting attributes: the auto-inferred schema of user-context keys the
129
+ platform has observed in evaluation calls. Read-only — populated by the
130
+ SDK hot path, surfaced here so you can see which keys (and value types)
131
+ are available when writing gate/experiment targeting rules.
132
+ - name: Metrics
133
+ description: |-
134
+ Metrics: the event-backed queries that drive tracking dashboards and
135
+ experiment success / guardrail measurement.
136
+
137
+ **Definition.** Each metric pins one source event (`event_name`), one
138
+ aggregation, and (for `sum`/`avg`/quantile) a numeric value label. The
139
+ query is expressed as the DSL string (`query`, e.g. `sum(purchase, amount)`)
140
+ or its typed IR (`query_ir`) — supply exactly one.
141
+
142
+ **Identity.** Keyed by a stable `name` (single segment or `folder.name`).
143
+ Resolve endpoints accept the `id` or the `name`.
144
+
145
+ **Deletion.** Archive (soft-delete). Blocked while the metric is attached
146
+ to a running experiment — stop those first.
147
+ - name: Events
148
+ parent: Metrics
149
+ description: |-
150
+ Events: the catalog of event names (and their typed properties) that metric queries reference.
151
+
152
+ **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.
153
+
154
+ **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.
155
+
156
+ **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.
157
+
158
+ **Deletion.** Soft-delete (the user-facing verb is `archive`). Blocked while any metric still references the event — delete those metrics first.
159
+ - name: Ops
160
+ description: |-
161
+ Operational queue: the unified table of bug reports, feature requests, and
162
+ auto-filed error/alert tickets, all over `/api/admin/ops`. One `create`
163
+ endpoint files either user type (`type: bug | feature_request`); list, get,
164
+ update, and link-pr are unified across every type. Also exposes the
165
+ `notify` escalation bell and the read-only Slack-channels list used to
166
+ resolve alert-rule notification targets.
167
+
168
+ **Handles.** A queue item is addressed by its per-project `number` (e.g. `7`)
169
+ or its full id — the API resolves either.
170
+ - name: Alerts
171
+ parent: Ops
172
+ x-cli:
173
+ aliases:
174
+ - ar
175
+ description: |-
176
+ Alert rules: the metric-threshold definitions the analysis cron evaluates each run.
177
+
178
+ **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.
179
+
180
+ **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.
181
+
182
+ **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.
183
+ - name: Projects
184
+ description: |-
185
+ Projects: the account-level container every other resource is scoped to.
186
+
187
+ **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.
188
+
189
+ **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.
190
+ - name: i18n
191
+ description: |-
192
+ String Manager (i18n): the worker-safe REST surface — locale profiles, the
193
+ insert-only key push, single-key overwrite, chunk publish, and the read-only
194
+ key/draft listings.
195
+
196
+ The fs/AST parts (scan, validate, install-loader, codemod) are NOT part of
197
+ this API — they stay in the fs-having CLI/MCP.
198
+ - name: Profiles
199
+ parent: i18n
200
+ description: Locale profiles (e.g. `en:prod`) — create, list, and publish a profile's chunks to the CDN.
201
+ - name: Keys
202
+ parent: i18n
203
+ description: Translation keys — the insert-only push, single-key overwrite, and key listing.
204
+ - name: Drafts
205
+ parent: i18n
206
+ description: Machine-translation drafts awaiting review before publish.
207
+ - name: Errors
208
+ description: |-
209
+ Tracked production errors: the deduplicated, fingerprinted error stream the
210
+ SDK + framework error sinks feed. Read-only list/get plus a status update
211
+ (`open`/`resolved`/`ignored`), an auto-file-to-GitHub-issue action, and a
212
+ time-series rollup. Errors are ingestion-only — there is no create route.
213
+ - name: Trigger
214
+ parent: Ops
215
+ description: |-
216
+ Recurring coding-agent triggers: the scheduled, unattended runs that burn
217
+ down the ops queue in `--pr` mode (one PR per fixed item; nothing
218
+ auto-merges). Shipeasy can fire four providers directly — Claude routines,
219
+ Cursor cloud agents, Copilot cloud agents, and Google Jules (the Gemini
220
+ path) — registered here as trigger connectors (idempotent per provider
221
+ key). Other platforms (Codex, Windsurf, Cline, OpenClaw, OpenCode,
222
+ Continue) schedule on their own surface — typically a GitHub Actions
223
+ `schedule:` cron running the platform's headless CLI with the shared
224
+ trigger prompt.
225
+ - name: Connectors
226
+ description: |-
227
+ Outbound integrations: the per-project destinations feedback + trigger
228
+ events are dispatched to (GitHub, Google Sheets, Slack, and the
229
+ Claude/Cursor/Copilot/Jules autopilot triggers). CRUD plus a manual
230
+ `fire` (trigger-only) and a `test` payload.
231
+ - name: API Keys
232
+ description: |-
233
+ Admin + SDK key management: mint, list, and revoke the `sdk_*` keys that
234
+ authenticate every other endpoint. The plaintext key is returned exactly
235
+ once, on create. Revoke is the rotation verb.
236
+ paths:
237
+ /api/admin/gates:
238
+ $ref: ./paths/gates.yaml#/~1api~1admin~1gates
239
+ /api/admin/gates/{id}:
240
+ $ref: ./paths/gates.yaml#/~1api~1admin~1gates~1{id}
241
+ /api/admin/gates/{id}/enable:
242
+ $ref: ./paths/gates.yaml#/~1api~1admin~1gates~1{id}~1enable
243
+ /api/admin/gates/{id}/disable:
244
+ $ref: ./paths/gates.yaml#/~1api~1admin~1gates~1{id}~1disable
245
+ /api/admin/experiments:
246
+ $ref: ./paths/experiments.yaml#/~1api~1admin~1experiments
247
+ /api/admin/experiments/{id}:
248
+ $ref: ./paths/experiments.yaml#/~1api~1admin~1experiments~1{id}
249
+ /api/admin/experiments/{id}/status:
250
+ $ref: ./paths/experiments.yaml#/~1api~1admin~1experiments~1{id}~1status
251
+ /api/admin/experiments/{id}/metrics:
252
+ $ref: ./paths/experiments.yaml#/~1api~1admin~1experiments~1{id}~1metrics
253
+ /api/admin/experiments/{id}/results:
254
+ $ref: ./paths/experiments.yaml#/~1api~1admin~1experiments~1{id}~1results
255
+ /api/admin/experiments/{id}/timeseries:
256
+ $ref: ./paths/experiments.yaml#/~1api~1admin~1experiments~1{id}~1timeseries
257
+ /api/admin/experiments/{id}/reanalyze:
258
+ $ref: ./paths/experiments.yaml#/~1api~1admin~1experiments~1{id}~1reanalyze
259
+ /api/admin/configs:
260
+ $ref: ./paths/configs.yaml#/~1api~1admin~1configs
261
+ /api/admin/configs/{id}:
262
+ $ref: ./paths/configs.yaml#/~1api~1admin~1configs~1{id}
263
+ /api/admin/configs/{id}/drafts:
264
+ $ref: ./paths/configs.yaml#/~1api~1admin~1configs~1{id}~1drafts
265
+ /api/admin/configs/{id}/publish:
266
+ $ref: ./paths/configs.yaml#/~1api~1admin~1configs~1{id}~1publish
267
+ /api/admin/configs/{id}/activity:
268
+ $ref: ./paths/configs.yaml#/~1api~1admin~1configs~1{id}~1activity
269
+ /api/admin/configs/{id}/schema:
270
+ $ref: ./paths/configs.yaml#/~1api~1admin~1configs~1{id}~1schema
271
+ /api/admin/killswitches:
272
+ $ref: ./paths/killswitches.yaml#/~1api~1admin~1killswitches
273
+ /api/admin/killswitches/{id}:
274
+ $ref: ./paths/killswitches.yaml#/~1api~1admin~1killswitches~1{id}
275
+ /api/admin/killswitches/{id}/switch:
276
+ $ref: ./paths/killswitches.yaml#/~1api~1admin~1killswitches~1{id}~1switch
277
+ /api/admin/killswitches/{id}/value:
278
+ $ref: ./paths/killswitches.yaml#/~1api~1admin~1killswitches~1{id}~1value
279
+ /api/admin/universes:
280
+ $ref: ./paths/universes.yaml#/~1api~1admin~1universes
281
+ /api/admin/universes/{id}:
282
+ $ref: ./paths/universes.yaml#/~1api~1admin~1universes~1{id}
283
+ /api/admin/gates/templates:
284
+ $ref: ./paths/gate-templates.yaml#/~1api~1admin~1gates~1templates
285
+ /api/admin/gates/templates/{id}:
286
+ $ref: ./paths/gate-templates.yaml#/~1api~1admin~1gates~1templates~1{id}
287
+ /api/admin/attributes:
288
+ $ref: ./paths/attributes.yaml#/~1api~1admin~1attributes
289
+ /api/admin/attributes/{id}:
290
+ $ref: ./paths/attributes.yaml#/~1api~1admin~1attributes~1{id}
291
+ /api/admin/metrics:
292
+ $ref: ./paths/metrics.yaml#/~1api~1admin~1metrics
293
+ /api/admin/metrics/{id}:
294
+ $ref: ./paths/metrics.yaml#/~1api~1admin~1metrics~1{id}
295
+ /api/admin/events:
296
+ $ref: ./paths/events.yaml#/~1api~1admin~1events
297
+ /api/admin/events/{id}:
298
+ $ref: ./paths/events.yaml#/~1api~1admin~1events~1{id}
299
+ /api/admin/events/{id}/approve:
300
+ $ref: ./paths/events.yaml#/~1api~1admin~1events~1{id}~1approve
301
+ /api/admin/ops:
302
+ $ref: ./paths/ops.yaml#/~1api~1admin~1ops
303
+ /api/admin/ops/{handle}:
304
+ $ref: ./paths/ops.yaml#/~1api~1admin~1ops~1{handle}
305
+ /api/admin/ops/{handle}/link-pr:
306
+ $ref: ./paths/ops.yaml#/~1api~1admin~1ops~1{handle}~1link-pr
307
+ /api/admin/notifications:
308
+ $ref: ./paths/ops.yaml#/~1api~1admin~1notifications
309
+ /api/admin/slack/channels:
310
+ $ref: ./paths/ops.yaml#/~1api~1admin~1slack~1channels
311
+ /api/admin/alert-rules:
312
+ $ref: ./paths/alert-rules.yaml#/~1api~1admin~1alert-rules
313
+ /api/admin/alert-rules/{id}:
314
+ $ref: ./paths/alert-rules.yaml#/~1api~1admin~1alert-rules~1{id}
315
+ /api/admin/projects/current:
316
+ $ref: ./paths/projects.yaml#/~1api~1admin~1projects~1current
317
+ /api/admin/projects/upsert:
318
+ $ref: ./paths/projects.yaml#/~1api~1admin~1projects~1upsert
319
+ /api/admin/projects/{id}:
320
+ $ref: ./paths/projects.yaml#/~1api~1admin~1projects~1{id}
321
+ /api/admin/i18n/profiles:
322
+ $ref: ./paths/i18n.yaml#/~1api~1admin~1i18n~1profiles
323
+ /api/admin/i18n/keys:
324
+ $ref: ./paths/i18n.yaml#/~1api~1admin~1i18n~1keys
325
+ /api/admin/i18n/keys/{id}:
326
+ $ref: ./paths/i18n.yaml#/~1api~1admin~1i18n~1keys~1{id}
327
+ /api/admin/i18n/drafts:
328
+ $ref: ./paths/i18n.yaml#/~1api~1admin~1i18n~1drafts
329
+ /api/admin/i18n/drafts/{draftId}:
330
+ $ref: ./paths/i18n.yaml#/~1api~1admin~1i18n~1drafts~1{draftId}
331
+ /api/admin/i18n/profiles/{profileId}/publish:
332
+ $ref: ./paths/i18n.yaml#/~1api~1admin~1i18n~1profiles~1{profileId}~1publish
333
+ /api/admin/i18n/set:
334
+ $ref: ./paths/i18n.yaml#/~1api~1admin~1i18n~1set
335
+ /api/admin/errors:
336
+ $ref: ./paths/errors.yaml#/~1api~1admin~1errors
337
+ /api/admin/errors/{id}:
338
+ $ref: ./paths/errors.yaml#/~1api~1admin~1errors~1{id}
339
+ /api/admin/errors/{id}/file:
340
+ $ref: ./paths/errors.yaml#/~1api~1admin~1errors~1{id}~1file
341
+ /api/admin/errors/{id}/series:
342
+ $ref: ./paths/errors.yaml#/~1api~1admin~1errors~1{id}~1series
343
+ /api/admin/connectors:
344
+ $ref: ./paths/connectors.yaml#/~1api~1admin~1connectors
345
+ /api/admin/connectors/{id}:
346
+ $ref: ./paths/connectors.yaml#/~1api~1admin~1connectors~1{id}
347
+ /api/admin/connectors/{id}/fire:
348
+ $ref: ./paths/connectors.yaml#/~1api~1admin~1connectors~1{id}~1fire
349
+ /api/admin/connectors/{id}/test:
350
+ $ref: ./paths/connectors.yaml#/~1api~1admin~1connectors~1{id}~1test
351
+ /api/admin/connectors/{id}/trigger:
352
+ $ref: ./paths/connectors.yaml#/~1api~1admin~1connectors~1{id}~1trigger
353
+ /api/admin/connectors/trigger:
354
+ $ref: ./paths/connectors.yaml#/~1api~1admin~1connectors~1trigger
355
+ /api/admin/keys:
356
+ $ref: ./paths/keys.yaml#/~1api~1admin~1keys
357
+ /api/admin/keys/{id}/revoke:
358
+ $ref: ./paths/keys.yaml#/~1api~1admin~1keys~1{id}~1revoke
359
+ /api/admin/search:
360
+ $ref: ./paths/search.yaml#/~1api~1admin~1search
361
+ components:
362
+ securitySchemes:
363
+ bearerSdkKey:
364
+ type: http
365
+ scheme: bearer
366
+ bearerFormat: sdk_admin_*
367
+ description: 'Pass an admin SDK key as `Authorization: Bearer sdk_admin_…`. Mint via `POST /api/admin/keys` with `type: "admin"`.'
@@ -0,0 +1,258 @@
1
+ /api/admin/alert-rules:
2
+ get:
3
+ operationId: listAlertRules
4
+ summary: List alert rules
5
+ description: |-
6
+ 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.
7
+
8
+ **Use case:** Audit which metrics have alerting configured — for example to confirm an on-call threshold is set before a launch.
9
+ tags:
10
+ - Alerts
11
+ parameters:
12
+ - $ref: ../components/parameters.yaml#/ProjectId
13
+ - $ref: ../components/parameters.yaml#/Q
14
+ responses:
15
+ "200":
16
+ description: List alert rules
17
+ content:
18
+ application/json:
19
+ schema:
20
+ $ref: ../components/schemas/alert-rules.yaml#/ListAlertRulesResponse
21
+ example:
22
+ - id: ar_01j7w8a1b2c3d4e5f6g7h8i9j0
23
+ name: Checkout error rate
24
+ metricId: met_01j6abc2d3e4f5g6h7i8j9k0l1
25
+ metricName: checkout_errors
26
+ comparator: gt
27
+ threshold: 50
28
+ windowHours: 24
29
+ severity: warn
30
+ enabled: true
31
+ notify: null
32
+ createdAt: 2026-04-12T10:14:08.000Z
33
+ updatedAt: 2026-04-12T10:14:08.000Z
34
+ "400":
35
+ $ref: ../components/responses.yaml#/BadRequest
36
+ "401":
37
+ $ref: ../components/responses.yaml#/Unauthorized
38
+ "403":
39
+ $ref: ../components/responses.yaml#/Forbidden
40
+ "404":
41
+ $ref: ../components/responses.yaml#/NotFound
42
+ "409":
43
+ $ref: ../components/responses.yaml#/Conflict
44
+ "422":
45
+ $ref: ../components/responses.yaml#/UnprocessableEntity
46
+ x-error-codes:
47
+ - BAD_REQUEST
48
+ - UNAUTHORIZED
49
+ - FORBIDDEN
50
+ x-cli:
51
+ name: list
52
+ post:
53
+ operationId: createAlertRule
54
+ summary: Create an alert rule
55
+ description: |-
56
+ Creates a metric-threshold alert rule. `name`, `metricId`, `comparator`, and `threshold` are required; `windowHours` defaults to `24`, `severity` to `warn`, and `enabled` to `true`.
57
+
58
+ 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.
59
+
60
+ **Use cases**
61
+
62
+ - **Threshold alert** — warn when an error/latency metric crosses a value over a rolling window.
63
+ - **Routed alert** — set `notify` to page a specific Slack channel or on-call email instead of the project default.
64
+ tags:
65
+ - Alerts
66
+ parameters:
67
+ - $ref: ../components/parameters.yaml#/ProjectId
68
+ requestBody:
69
+ required: true
70
+ content:
71
+ application/json:
72
+ schema:
73
+ $ref: ../components/schemas/alert-rules.yaml#/CreateAlertRuleRequest
74
+ examples:
75
+ minimal:
76
+ summary: Minimal — alert when a metric exceeds a threshold
77
+ description: Smallest valid body. Warns when the metric exceeds 50 over the default 24h window, with no per-rule delivery target.
78
+ value:
79
+ name: Checkout error rate
80
+ metricId: met_01j6abc2d3e4f5g6h7i8j9k0l1
81
+ comparator: gt
82
+ threshold: 50
83
+ targeted:
84
+ summary: Full — custom window, severity, and Slack/email target
85
+ description: A `danger` rule over a 1h window that posts to a Slack channel and emails on-call. The Slack channel must come from a connected connector.
86
+ value:
87
+ name: Checkout error spike
88
+ metricId: met_01j6abc2d3e4f5g6h7i8j9k0l1
89
+ comparator: gt
90
+ threshold: 100
91
+ windowHours: 1
92
+ severity: danger
93
+ notify:
94
+ slackChannel:
95
+ id: C0123ABCD
96
+ name: incidents
97
+ email: oncall@acme.com
98
+ responses:
99
+ "201":
100
+ description: Create an alert rule
101
+ content:
102
+ application/json:
103
+ schema:
104
+ $ref: ../components/schemas/alert-rules.yaml#/CreateAlertRuleResponse
105
+ example:
106
+ id: ar_01j7w8a1b2c3d4e5f6g7h8i9j0
107
+ links:
108
+ UpdateAlertRule:
109
+ operationId: updateAlertRule
110
+ parameters: { id: $response.body#/id }
111
+ DeleteAlertRule:
112
+ operationId: deleteAlertRule
113
+ parameters: { id: $response.body#/id }
114
+ "400":
115
+ $ref: ../components/responses.yaml#/BadRequest
116
+ "401":
117
+ $ref: ../components/responses.yaml#/Unauthorized
118
+ "403":
119
+ $ref: ../components/responses.yaml#/Forbidden
120
+ "404":
121
+ $ref: ../components/responses.yaml#/NotFound
122
+ "409":
123
+ $ref: ../components/responses.yaml#/Conflict
124
+ "422":
125
+ $ref: ../components/responses.yaml#/UnprocessableEntity
126
+ x-error-codes:
127
+ - BAD_REQUEST
128
+ - UNAUTHORIZED
129
+ - FORBIDDEN
130
+ - ALREADY_EXISTS
131
+ - REFERENCED_NOT_FOUND
132
+ - VALIDATION
133
+ x-cli:
134
+ name: create
135
+ /api/admin/alert-rules/{id}:
136
+ patch:
137
+ operationId: updateAlertRule
138
+ summary: Update an alert rule
139
+ description: |-
140
+ 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).
141
+
142
+ Pass `"notify": null` to revert the rule's delivery target back to the project default.
143
+
144
+ **Use cases**
145
+
146
+ - **Tune sensitivity** — change `threshold`/`comparator`/`windowHours` as the metric's baseline shifts.
147
+ - **Pause without losing config** — `{ "enabled": false }` instead of deleting the rule.
148
+ tags:
149
+ - Alerts
150
+ parameters:
151
+ - $ref: ../components/parameters.yaml#/ProjectId
152
+ - name: id
153
+ in: path
154
+ required: true
155
+ description: Stable opaque alert-rule id (`ar_…`) or the rule's `name`.
156
+ schema:
157
+ $ref: ../components/schemas/common.yaml#/ResourceId
158
+ requestBody:
159
+ required: true
160
+ content:
161
+ application/json:
162
+ schema:
163
+ $ref: ../components/schemas/alert-rules.yaml#/UpdateAlertRuleRequest
164
+ examples:
165
+ raiseThreshold:
166
+ summary: Raise the threshold
167
+ description: Bump the alerting threshold without touching anything else.
168
+ value:
169
+ threshold: 100
170
+ disable:
171
+ summary: Disable the rule
172
+ description: Stop the cron from evaluating the rule.
173
+ value:
174
+ enabled: false
175
+ clearTarget:
176
+ summary: Revert to the project default target
177
+ description: Drop the per-rule Slack/email target and fall back to project defaults.
178
+ value:
179
+ notify: null
180
+ responses:
181
+ "200":
182
+ description: Update an alert rule
183
+ content:
184
+ application/json:
185
+ schema:
186
+ $ref: ../components/schemas/alert-rules.yaml#/UpdateAlertRuleResponse
187
+ example:
188
+ id: ar_01j7w8a1b2c3d4e5f6g7h8i9j0
189
+ "400":
190
+ $ref: ../components/responses.yaml#/BadRequest
191
+ "401":
192
+ $ref: ../components/responses.yaml#/Unauthorized
193
+ "403":
194
+ $ref: ../components/responses.yaml#/Forbidden
195
+ "404":
196
+ $ref: ../components/responses.yaml#/NotFound
197
+ "409":
198
+ $ref: ../components/responses.yaml#/Conflict
199
+ "422":
200
+ $ref: ../components/responses.yaml#/UnprocessableEntity
201
+ x-error-codes:
202
+ - BAD_REQUEST
203
+ - UNAUTHORIZED
204
+ - FORBIDDEN
205
+ - NOT_FOUND
206
+ - IMMUTABLE_FIELD
207
+ - VALIDATION
208
+ x-cli:
209
+ name: update
210
+ positional:
211
+ - id
212
+ delete:
213
+ operationId: deleteAlertRule
214
+ summary: Delete an alert rule
215
+ description: |-
216
+ 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.
217
+
218
+ **Use case:** Remove an alert rule that is no longer needed, or as the first half of repointing a rule at a different metric.
219
+ tags:
220
+ - Alerts
221
+ parameters:
222
+ - $ref: ../components/parameters.yaml#/ProjectId
223
+ - name: id
224
+ in: path
225
+ required: true
226
+ description: Stable opaque alert-rule id (`ar_…`) or the rule's `name`.
227
+ schema:
228
+ $ref: ../components/schemas/common.yaml#/ResourceId
229
+ responses:
230
+ "200":
231
+ description: Delete an alert rule
232
+ content:
233
+ application/json:
234
+ schema:
235
+ $ref: ../components/schemas/alert-rules.yaml#/DeleteAlertRuleResponse
236
+ example:
237
+ ok: true
238
+ "400":
239
+ $ref: ../components/responses.yaml#/BadRequest
240
+ "401":
241
+ $ref: ../components/responses.yaml#/Unauthorized
242
+ "403":
243
+ $ref: ../components/responses.yaml#/Forbidden
244
+ "404":
245
+ $ref: ../components/responses.yaml#/NotFound
246
+ "409":
247
+ $ref: ../components/responses.yaml#/Conflict
248
+ "422":
249
+ $ref: ../components/responses.yaml#/UnprocessableEntity
250
+ x-error-codes:
251
+ - BAD_REQUEST
252
+ - UNAUTHORIZED
253
+ - FORBIDDEN
254
+ - NOT_FOUND
255
+ x-cli:
256
+ name: archive
257
+ positional:
258
+ - id