@shipeasy/openapi 1.1.0 → 1.4.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.
- package/dist/index.js +49 -14
- package/dist/resources/experiments.d.ts +18 -30
- package/dist/resources/experiments.js +26 -8
- package/dist/resources/gates.d.ts +95 -0
- package/dist/resources/gates.js +23 -6
- package/dist/resources/index.d.ts +111 -30
- package/dist/resources/index.js +49 -14
- package/dist/schemas/experiments.d.ts +4 -20
- package/dist/schemas/experiments.js +7 -2
- package/dist/schemas/gates.d.ts +83 -1
- package/dist/schemas/gates.js +24 -6
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +31 -8
- package/openapi.json +1533 -236
- package/package.json +1 -1
package/openapi.json
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"name": "Experiments",
|
|
32
|
-
"description": "A/B/n experiments: randomised group assignment plus the analysis pipeline (t-test, sequential testing, SRM detection) on top of a universe.\n\n**Identity.** Stable `name` (a-z, 0-9, `_`/`-`, max 64 chars). Immutable after create.\n\n**Lifecycle.** `draft → running → stopped → archived`. Transition via `POST /{id}/status`.
|
|
32
|
+
"description": "A/B/n experiments: randomised group assignment plus the analysis pipeline (t-test, sequential testing, SRM detection) on top of a universe.\n\n**Identity.** Stable `name` (a-z, 0-9, `_`/`-`, max 64 chars). Immutable after create.\n\n**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.\n\n**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.\n\n**Immutable while running.** `allocation_pct`, `groups`, `salt`, `universe`, `params` cannot be edited on a running experiment — stop it first.\n\n**Metrics.** Attach via `POST /{id}/metrics`. Each metric has a role: `goal` drives the decision, `guardrail` blocks ship on regression, `secondary` is informational.\n\n**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."
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"name": "Configs",
|
|
@@ -50,7 +50,9 @@
|
|
|
50
50
|
"operationId": "listGates",
|
|
51
51
|
"summary": "List feature gates",
|
|
52
52
|
"description": "Returns a single page of gates ordered by `updated_at desc, id desc`. Use the `cursor` query parameter to paginate.\n\n**Use case:** 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.",
|
|
53
|
-
"tags": [
|
|
53
|
+
"tags": [
|
|
54
|
+
"Gates"
|
|
55
|
+
],
|
|
54
56
|
"parameters": [
|
|
55
57
|
{
|
|
56
58
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -81,7 +83,11 @@
|
|
|
81
83
|
{
|
|
82
84
|
"attr": "country",
|
|
83
85
|
"op": "in",
|
|
84
|
-
"value": [
|
|
86
|
+
"value": [
|
|
87
|
+
"US",
|
|
88
|
+
"CA",
|
|
89
|
+
"GB"
|
|
90
|
+
]
|
|
85
91
|
},
|
|
86
92
|
{
|
|
87
93
|
"attr": "plan",
|
|
@@ -128,7 +134,9 @@
|
|
|
128
134
|
"operationId": "createGate",
|
|
129
135
|
"summary": "Create a feature gate",
|
|
130
136
|
"description": "Creates a new gate. Default `enabled: true` at the supplied `rollout_pct` (`0` = fully dark).\n\nOnly `name` is required. Request fields use snake_case (`owner_email`); the GET response returns camelCase (`ownerEmail`, `groupName`).\n\nReturns `409` if `name` already exists in the project (case-sensitive).\n\n**Use cases**\n\n- **Dark create + ramp later** — `{ \"name\": \"checkout_v2\" }` at 0% rollout. Ramp via PATCH after deploy validation.\n- **Targeted rollout** — supply `rules` to gate the caller (e.g. only `plan = pro` users) plus a `rollout_pct` to bucket within that audience.\n- **Gatekeeper stack** — supply `stack` instead of `rules`/`rollout_pct` for `internal ∪ beta ∪ public` fall-through. Stack entries evaluated top-to-bottom; first match wins.\n- **Dashboard metadata** — populate `title`, `description`, `folder`, `group`, `owner_email` so the admin UI is self-documenting from day one.\n- **Disabled on create** — pre-provision with `enabled: false` for a future launch; flip on with `POST /{id}/enable` at go-live.",
|
|
131
|
-
"tags": [
|
|
137
|
+
"tags": [
|
|
138
|
+
"Gates"
|
|
139
|
+
],
|
|
132
140
|
"parameters": [
|
|
133
141
|
{
|
|
134
142
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -159,7 +167,11 @@
|
|
|
159
167
|
{
|
|
160
168
|
"attr": "country",
|
|
161
169
|
"op": "in",
|
|
162
|
-
"value": [
|
|
170
|
+
"value": [
|
|
171
|
+
"US",
|
|
172
|
+
"CA",
|
|
173
|
+
"GB"
|
|
174
|
+
]
|
|
163
175
|
},
|
|
164
176
|
{
|
|
165
177
|
"attr": "plan",
|
|
@@ -273,7 +285,9 @@
|
|
|
273
285
|
"operationId": "updateGate",
|
|
274
286
|
"summary": "Update a feature gate",
|
|
275
287
|
"description": "Partial update — only supplied fields change. Array fields (`rules`, `stack`) **replace** wholesale; there is no merge or append.\n\n`name` and the gate id are immutable. The response carries only `{ id }` — re-fetch via `GET /api/admin/gates` for the new row.\n\n**Use cases**\n\n- **Ramp rollout** — `{ \"rollout_pct\": 5000 }` for 50%. Basis points (0–10000); `100` = 1%.\n- **Kill switch** — `{ \"enabled\": false }`. Forces evaluation to `false` for every caller regardless of rules/rollout. Re-enable with `POST /{id}/enable` or `{ \"enabled\": true }`.\n- **Modify a rule's `in` set** — send the full new `rules` array. To add `'GB'` to `['US','CA']`: `{ \"rules\": [{ \"attr\": \"country\", \"op\": \"in\", \"value\": [\"US\",\"CA\",\"GB\"] }] }`. No per-rule patch endpoint.\n- **Add targeting from scratch** — `{ \"rules\": [{ \"attr\": \"email\", \"op\": \"regex\", \"value\": \"@acme\\\\.com$\" }] }`.\n- **Switch to gatekeeper stack** — send a non-null `stack`. To revert to flat eval, send `{ \"stack\": null }`.\n- **Update metadata** — any subset of `title`, `description`, `folder`, `group`, `owner_email`.",
|
|
276
|
-
"tags": [
|
|
288
|
+
"tags": [
|
|
289
|
+
"Gates"
|
|
290
|
+
],
|
|
277
291
|
"parameters": [
|
|
278
292
|
{
|
|
279
293
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -318,7 +332,12 @@
|
|
|
318
332
|
{
|
|
319
333
|
"attr": "country",
|
|
320
334
|
"op": "in",
|
|
321
|
-
"value": [
|
|
335
|
+
"value": [
|
|
336
|
+
"US",
|
|
337
|
+
"CA",
|
|
338
|
+
"GB",
|
|
339
|
+
"AU"
|
|
340
|
+
]
|
|
322
341
|
},
|
|
323
342
|
{
|
|
324
343
|
"attr": "plan",
|
|
@@ -408,7 +427,9 @@
|
|
|
408
427
|
"operationId": "deleteGate",
|
|
409
428
|
"summary": "Delete a feature gate",
|
|
410
429
|
"description": "Soft-deletes the gate. Returns 409 if the gate is still referenced by a running experiment as a targeting gate — stop the experiment first.\n\n**Use case:** Tear down a gate after a feature has fully shipped and the rollout flag is no longer needed.",
|
|
411
|
-
"tags": [
|
|
430
|
+
"tags": [
|
|
431
|
+
"Gates"
|
|
432
|
+
],
|
|
412
433
|
"parameters": [
|
|
413
434
|
{
|
|
414
435
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -463,7 +484,9 @@
|
|
|
463
484
|
"operationId": "enableGate",
|
|
464
485
|
"summary": "Enable a gate",
|
|
465
486
|
"description": "Sets `enabled: true`. The current `rollout_pct` is preserved.\n\n**Use case:** Re-enable a previously disabled gate without re-issuing a full update.",
|
|
466
|
-
"tags": [
|
|
487
|
+
"tags": [
|
|
488
|
+
"Gates"
|
|
489
|
+
],
|
|
467
490
|
"parameters": [
|
|
468
491
|
{
|
|
469
492
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -519,7 +542,9 @@
|
|
|
519
542
|
"operationId": "disableGate",
|
|
520
543
|
"summary": "Disable a gate",
|
|
521
544
|
"description": "Sets `enabled: false` so the gate evaluates to `false` for every caller, regardless of `rollout_pct` or `rules`. Use as a quick kill switch.\n\n**Use case:** Flip a gate off in production without redeploying — the canonical kill-switch flow.",
|
|
522
|
-
"tags": [
|
|
545
|
+
"tags": [
|
|
546
|
+
"Gates"
|
|
547
|
+
],
|
|
523
548
|
"parameters": [
|
|
524
549
|
{
|
|
525
550
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -575,7 +600,9 @@
|
|
|
575
600
|
"operationId": "listExperiments",
|
|
576
601
|
"summary": "List experiments",
|
|
577
602
|
"description": "Returns a single page of non-archived experiments ordered by `updated_at desc, id desc`. Use the `cursor` query parameter to paginate.\n\n**Use case:** 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`.",
|
|
578
|
-
"tags": [
|
|
603
|
+
"tags": [
|
|
604
|
+
"Experiments"
|
|
605
|
+
],
|
|
579
606
|
"parameters": [
|
|
580
607
|
{
|
|
581
608
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -664,7 +691,9 @@
|
|
|
664
691
|
"operationId": "createExperiment",
|
|
665
692
|
"summary": "Create an experiment",
|
|
666
693
|
"description": "Creates a new experiment in `draft` status. `name`, `universe`, and `groups` are required; everything else has sensible defaults.\n\nReturns `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.\n\n**Use cases**\n\n- **Minimal 50/50** — `name` + `universe` + two equal-weight groups.\n- **Targeted rollout** — supply `targeting_gate` to restrict the eligible audience and `allocation_pct` to enrol a slice of it.\n- **Multivariant** — three or more groups with weights summing to 10000.\n- **Sequential testing** — `sequential_testing: true` for Premium plans.",
|
|
667
|
-
"tags": [
|
|
694
|
+
"tags": [
|
|
695
|
+
"Experiments"
|
|
696
|
+
],
|
|
668
697
|
"parameters": [
|
|
669
698
|
{
|
|
670
699
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -813,7 +842,9 @@
|
|
|
813
842
|
"operationId": "getExperiment",
|
|
814
843
|
"summary": "Get one experiment",
|
|
815
844
|
"description": "Returns the full experiment row including groups, params, allocation, and lifecycle timestamps.\n\n**Use case:** Fetch one experiment to render the detail page or to inspect its current allocation and group weights.",
|
|
816
|
-
"tags": [
|
|
845
|
+
"tags": [
|
|
846
|
+
"Experiments"
|
|
847
|
+
],
|
|
817
848
|
"parameters": [
|
|
818
849
|
{
|
|
819
850
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -900,7 +931,9 @@
|
|
|
900
931
|
"operationId": "updateExperiment",
|
|
901
932
|
"summary": "Update an experiment",
|
|
902
933
|
"description": "Partial update. `allocation_pct`, `groups`, `salt`, `universe`, `params` are **immutable while running** — returns `409` if you try. Stop the experiment first.\n\nEditing `groups` while in `draft` is fine; weights must still sum to 10000.\n\n**Use cases**\n\n- **Update metadata** — `description`, `tag`, `targeting_gate` editable any time.\n- **Ramp before launch** — set `allocation_pct` while still in `draft`.\n- **Tighten significance** — `significance_threshold` (Pro+).\n- **Rewire groups** — replace `groups` wholesale while in `draft`; immutable once running.",
|
|
903
|
-
"tags": [
|
|
934
|
+
"tags": [
|
|
935
|
+
"Experiments"
|
|
936
|
+
],
|
|
904
937
|
"parameters": [
|
|
905
938
|
{
|
|
906
939
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1003,7 +1036,9 @@
|
|
|
1003
1036
|
"operationId": "deleteExperiment",
|
|
1004
1037
|
"summary": "Delete an experiment",
|
|
1005
1038
|
"description": "Archives the experiment (soft-delete via status transition). Returns `409` if the experiment is still `running` — stop it first.\n\n**Use case:** Tear down an experiment after the analysis is signed off.",
|
|
1006
|
-
"tags": [
|
|
1039
|
+
"tags": [
|
|
1040
|
+
"Experiments"
|
|
1041
|
+
],
|
|
1007
1042
|
"parameters": [
|
|
1008
1043
|
{
|
|
1009
1044
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1057,8 +1092,10 @@
|
|
|
1057
1092
|
"post": {
|
|
1058
1093
|
"operationId": "setExperimentStatus",
|
|
1059
1094
|
"summary": "Transition experiment status",
|
|
1060
|
-
"description": "Drives the experiment lifecycle. Allowed transitions:\n\n- `draft → running` — starts allocation. Bumps the `startedAt` timestamp.\n- `running → stopped` — halts allocation. Existing exposures stay in the dataset.\n- `stopped → archived` — soft-delete.\n- `draft → archived` — discard an unstarted experiment.\n\nRestarting an `archived` experiment is not allowed
|
|
1061
|
-
"tags": [
|
|
1095
|
+
"description": "Drives the experiment lifecycle. Allowed transitions:\n\n- `draft → running` — starts allocation. Bumps the `startedAt` timestamp.\n- `running → stopped` — halts allocation. Existing exposures stay in the dataset.\n- `stopped → archived` — soft-delete.\n- `draft → archived` — discard an unstarted experiment.\n- `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.\n\nRestarting 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`.\n\n**Use cases**\n\n- **Start** — `{ \"status\": \"running\" }` after wiring up the SDK and verifying targeting on staging.\n- **Stop** — `{ \"status\": \"stopped\" }` once the experiment hits its `min_runtime_days` and conclusive results land.\n- **Archive** — `{ \"status\": \"archived\" }` to soft-delete after sign-off.",
|
|
1096
|
+
"tags": [
|
|
1097
|
+
"Experiments"
|
|
1098
|
+
],
|
|
1062
1099
|
"parameters": [
|
|
1063
1100
|
{
|
|
1064
1101
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1101,6 +1138,13 @@
|
|
|
1101
1138
|
"value": {
|
|
1102
1139
|
"status": "archived"
|
|
1103
1140
|
}
|
|
1141
|
+
},
|
|
1142
|
+
"restore": {
|
|
1143
|
+
"summary": "Restore — archived → draft",
|
|
1144
|
+
"description": "Un-deletes a soft-deleted experiment so it can be re-completed and started. Allowed only if it never ran.",
|
|
1145
|
+
"value": {
|
|
1146
|
+
"status": "draft"
|
|
1147
|
+
}
|
|
1104
1148
|
}
|
|
1105
1149
|
}
|
|
1106
1150
|
}
|
|
@@ -1147,7 +1191,9 @@
|
|
|
1147
1191
|
"operationId": "setExperimentMetrics",
|
|
1148
1192
|
"summary": "Attach metrics",
|
|
1149
1193
|
"description": "Replaces the experiment's metric attachments wholesale. Each entry pairs an existing `metric_id` with a `role` (`goal` / `guardrail` / `secondary`).\n\nReturns `422` if any `metric_id` doesn't exist in the project. Pass `{ metrics: [] }` to detach everything.\n\n**Use cases**\n\n- **Standard setup** — one `goal`, one or two `guardrail`, optional `secondary` metrics for diagnostics.\n- **Detach all** — send `{ \"metrics\": [] }` before archiving.",
|
|
1150
|
-
"tags": [
|
|
1194
|
+
"tags": [
|
|
1195
|
+
"Experiments"
|
|
1196
|
+
],
|
|
1151
1197
|
"parameters": [
|
|
1152
1198
|
{
|
|
1153
1199
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1247,7 +1293,9 @@
|
|
|
1247
1293
|
"operationId": "getExperimentResults",
|
|
1248
1294
|
"summary": "Get analysis results",
|
|
1249
1295
|
"description": "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.\n\n**Use case:** Render the results table on the experiment detail page or drive an automated decision once a `goal` metric reaches significance.",
|
|
1250
|
-
"tags": [
|
|
1296
|
+
"tags": [
|
|
1297
|
+
"Experiments"
|
|
1298
|
+
],
|
|
1251
1299
|
"parameters": [
|
|
1252
1300
|
{
|
|
1253
1301
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1328,7 +1376,9 @@
|
|
|
1328
1376
|
"operationId": "getExperimentTimeseries",
|
|
1329
1377
|
"summary": "Get analysis timeseries",
|
|
1330
1378
|
"description": "Same row shape as `/results`, but returns every daily slice rather than the latest. Filter to a single metric with the `metric` query parameter.\n\n**Use case:** Drive a chart of metric movement over the experiment runtime, or sanity-check the lift is monotonic before deciding.",
|
|
1331
|
-
"tags": [
|
|
1379
|
+
"tags": [
|
|
1380
|
+
"Experiments"
|
|
1381
|
+
],
|
|
1332
1382
|
"parameters": [
|
|
1333
1383
|
{
|
|
1334
1384
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1418,7 +1468,9 @@
|
|
|
1418
1468
|
"operationId": "reanalyzeExperiment",
|
|
1419
1469
|
"summary": "Re-queue analysis",
|
|
1420
1470
|
"description": "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.\n\n**Use case:** Force-refresh results after wiring up a new metric without waiting for the next nightly cron tick.",
|
|
1421
|
-
"tags": [
|
|
1471
|
+
"tags": [
|
|
1472
|
+
"Experiments"
|
|
1473
|
+
],
|
|
1422
1474
|
"parameters": [
|
|
1423
1475
|
{
|
|
1424
1476
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1474,7 +1526,9 @@
|
|
|
1474
1526
|
"operationId": "listConfigs",
|
|
1475
1527
|
"summary": "List dynamic configs",
|
|
1476
1528
|
"description": "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.\n\n**Use case:** 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.",
|
|
1477
|
-
"tags": [
|
|
1529
|
+
"tags": [
|
|
1530
|
+
"Configs"
|
|
1531
|
+
],
|
|
1478
1532
|
"parameters": [
|
|
1479
1533
|
{
|
|
1480
1534
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1510,7 +1564,9 @@
|
|
|
1510
1564
|
}
|
|
1511
1565
|
}
|
|
1512
1566
|
},
|
|
1513
|
-
"required": [
|
|
1567
|
+
"required": [
|
|
1568
|
+
"tiers"
|
|
1569
|
+
]
|
|
1514
1570
|
},
|
|
1515
1571
|
"updatedAt": "2026-05-09T18:22:11.000Z",
|
|
1516
1572
|
"envs": {
|
|
@@ -1568,7 +1624,9 @@
|
|
|
1568
1624
|
"operationId": "createConfig",
|
|
1569
1625
|
"summary": "Create a dynamic config",
|
|
1570
1626
|
"description": "Creates a new config with the given `schema`. The initial `value` (or an empty object) is published as version 1 on **every** env.\n\nReturns `409` if `name` already exists in the project, `400` if `value` doesn't validate against `schema`.\n\n**Use cases**\n\n- **Minimal create** — `name` + `schema`. Initial value defaults to `{}`.\n- **Seeded create** — supply a flat `value` to publish the same object on every env.\n- **Per-env seed** — supply a `{ env: value }` map for different per-env starting values.",
|
|
1571
|
-
"tags": [
|
|
1627
|
+
"tags": [
|
|
1628
|
+
"Configs"
|
|
1629
|
+
],
|
|
1572
1630
|
"parameters": [
|
|
1573
1631
|
{
|
|
1574
1632
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1594,7 +1652,9 @@
|
|
|
1594
1652
|
"type": "array"
|
|
1595
1653
|
}
|
|
1596
1654
|
},
|
|
1597
|
-
"required": [
|
|
1655
|
+
"required": [
|
|
1656
|
+
"tiers"
|
|
1657
|
+
]
|
|
1598
1658
|
}
|
|
1599
1659
|
}
|
|
1600
1660
|
},
|
|
@@ -1611,7 +1671,9 @@
|
|
|
1611
1671
|
"type": "array"
|
|
1612
1672
|
}
|
|
1613
1673
|
},
|
|
1614
|
-
"required": [
|
|
1674
|
+
"required": [
|
|
1675
|
+
"tiers"
|
|
1676
|
+
]
|
|
1615
1677
|
},
|
|
1616
1678
|
"value": {
|
|
1617
1679
|
"tiers": [
|
|
@@ -1637,7 +1699,9 @@
|
|
|
1637
1699
|
"type": "array"
|
|
1638
1700
|
}
|
|
1639
1701
|
},
|
|
1640
|
-
"required": [
|
|
1702
|
+
"required": [
|
|
1703
|
+
"tiers"
|
|
1704
|
+
]
|
|
1641
1705
|
},
|
|
1642
1706
|
"value": {
|
|
1643
1707
|
"dev": {
|
|
@@ -1721,7 +1785,9 @@
|
|
|
1721
1785
|
"operationId": "getConfig",
|
|
1722
1786
|
"summary": "Get one config",
|
|
1723
1787
|
"description": "Returns config metadata plus the latest published values per env and any active draft values. Use this to fetch the JSON the editor renders.\n\n**Use case:** Fetch one config's current published values and any in-flight drafts.",
|
|
1724
|
-
"tags": [
|
|
1788
|
+
"tags": [
|
|
1789
|
+
"Configs"
|
|
1790
|
+
],
|
|
1725
1791
|
"parameters": [
|
|
1726
1792
|
{
|
|
1727
1793
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1758,7 +1824,9 @@
|
|
|
1758
1824
|
}
|
|
1759
1825
|
}
|
|
1760
1826
|
},
|
|
1761
|
-
"required": [
|
|
1827
|
+
"required": [
|
|
1828
|
+
"tiers"
|
|
1829
|
+
]
|
|
1762
1830
|
},
|
|
1763
1831
|
"updatedAt": "2026-05-09T18:22:11.000Z",
|
|
1764
1832
|
"envs": {
|
|
@@ -1860,7 +1928,9 @@
|
|
|
1860
1928
|
"operationId": "updateConfig",
|
|
1861
1929
|
"summary": "Update a dynamic config",
|
|
1862
1930
|
"description": "Partial update. When `value` is supplied it is **republished on every env** (new version per env). When `schema` is supplied it replaces the current schema; every existing value is re-validated.\n\nFor env-scoped edits, use the draft/publish flow (`PUT /{id}/drafts` then `POST /{id}/publish`) instead.\n\n**Use cases**\n\n- **Republish flat value** — `{ \"value\": {…} }` sets the same value on every env.\n- **Schema migration** — `{ \"schema\": {…} }` replaces the schema; existing values are re-validated.\n- **Env-scoped edits** — use `PUT /{id}/drafts` + `POST /{id}/publish` instead of PATCH.",
|
|
1863
|
-
"tags": [
|
|
1931
|
+
"tags": [
|
|
1932
|
+
"Configs"
|
|
1933
|
+
],
|
|
1864
1934
|
"parameters": [
|
|
1865
1935
|
{
|
|
1866
1936
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -1913,7 +1983,9 @@
|
|
|
1913
1983
|
"type": "integer"
|
|
1914
1984
|
}
|
|
1915
1985
|
},
|
|
1916
|
-
"required": [
|
|
1986
|
+
"required": [
|
|
1987
|
+
"tiers"
|
|
1988
|
+
]
|
|
1917
1989
|
}
|
|
1918
1990
|
}
|
|
1919
1991
|
}
|
|
@@ -1959,7 +2031,9 @@
|
|
|
1959
2031
|
"operationId": "deleteConfig",
|
|
1960
2032
|
"summary": "Delete a dynamic config",
|
|
1961
2033
|
"description": "Soft-deletes the config and rebuilds the project's flags KV blob.\n\n**Use case:** Tear down a config after its consumers have stopped reading it.",
|
|
1962
|
-
"tags": [
|
|
2034
|
+
"tags": [
|
|
2035
|
+
"Configs"
|
|
2036
|
+
],
|
|
1963
2037
|
"parameters": [
|
|
1964
2038
|
{
|
|
1965
2039
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2014,7 +2088,9 @@
|
|
|
2014
2088
|
"operationId": "saveConfigDraft",
|
|
2015
2089
|
"summary": "Save a draft value",
|
|
2016
2090
|
"description": "Stages a value for one env without publishing. The draft is validated against the config's current schema and stored alongside the `baseVersion` it was forked from.\n\nSaving over an existing draft overwrites it. Use `POST /{id}/publish` to promote it to a new published version.\n\n**Use case:** Iterate on a config value on dev without affecting prod — preview in staging, then publish.",
|
|
2017
|
-
"tags": [
|
|
2091
|
+
"tags": [
|
|
2092
|
+
"Configs"
|
|
2093
|
+
],
|
|
2018
2094
|
"parameters": [
|
|
2019
2095
|
{
|
|
2020
2096
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2102,7 +2178,9 @@
|
|
|
2102
2178
|
"operationId": "discardConfigDraft",
|
|
2103
2179
|
"summary": "Discard a draft",
|
|
2104
2180
|
"description": "Drops the in-flight draft on one env. Published values are unaffected.\n\n**Use case:** Abandon an in-progress draft after deciding not to ship it.",
|
|
2105
|
-
"tags": [
|
|
2181
|
+
"tags": [
|
|
2182
|
+
"Configs"
|
|
2183
|
+
],
|
|
2106
2184
|
"parameters": [
|
|
2107
2185
|
{
|
|
2108
2186
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2176,7 +2254,9 @@
|
|
|
2176
2254
|
"operationId": "publishConfigDraft",
|
|
2177
2255
|
"summary": "Publish a draft",
|
|
2178
2256
|
"description": "Promotes the staged draft on one env to a new published version. The draft must still validate against the current schema.\n\nReturns `404` if there is no draft for the given env.\n\n**Use case:** Ship a staged change once you've validated it on a lower env.",
|
|
2179
|
-
"tags": [
|
|
2257
|
+
"tags": [
|
|
2258
|
+
"Configs"
|
|
2259
|
+
],
|
|
2180
2260
|
"parameters": [
|
|
2181
2261
|
{
|
|
2182
2262
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2259,7 +2339,9 @@
|
|
|
2259
2339
|
"operationId": "listConfigActivity",
|
|
2260
2340
|
"summary": "List config activity",
|
|
2261
2341
|
"description": "Returns recent audit rows for one config (create, update, draft.save, publish, delete) ordered newest first. Use the `limit` query parameter to cap the result (1–100, default 20).\n\n**Use case:** Render the activity panel in the config editor or drive a slack notification on publish events.",
|
|
2262
|
-
"tags": [
|
|
2342
|
+
"tags": [
|
|
2343
|
+
"Configs"
|
|
2344
|
+
],
|
|
2263
2345
|
"parameters": [
|
|
2264
2346
|
{
|
|
2265
2347
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2336,7 +2418,9 @@
|
|
|
2336
2418
|
"operationId": "listKillswitches",
|
|
2337
2419
|
"summary": "List killswitches",
|
|
2338
2420
|
"description": "Returns a single page of killswitches ordered by `updated_at desc, id desc`. Each row includes the latest published `value`/`switches`/`version` per env.\n\n**Use case:** Snapshot every killswitch in the project — e.g. to render an incident-response runbook listing every kill and its current trip state.",
|
|
2339
|
-
"tags": [
|
|
2421
|
+
"tags": [
|
|
2422
|
+
"Killswitches"
|
|
2423
|
+
],
|
|
2340
2424
|
"parameters": [
|
|
2341
2425
|
{
|
|
2342
2426
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2414,7 +2498,9 @@
|
|
|
2414
2498
|
"operationId": "createKillswitch",
|
|
2415
2499
|
"summary": "Create a killswitch",
|
|
2416
2500
|
"description": "Creates a new killswitch with `value` (default `false`) applied to **every** env at version 1.\n\nReturns `409` if `name` already exists in the project.\n\n**Use cases**\n\n- **Untripped create** — `{ \"name\": \"payments.checkout\" }`. Provision the kill ahead of an incident.\n- **Pre-tripped** — `{ \"value\": true }` to ship the killswitch already engaged.\n- **With switches** — seed `switches` to carve out per-region/per-tenant kills from day one.",
|
|
2417
|
-
"tags": [
|
|
2501
|
+
"tags": [
|
|
2502
|
+
"Killswitches"
|
|
2503
|
+
],
|
|
2418
2504
|
"parameters": [
|
|
2419
2505
|
{
|
|
2420
2506
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2501,7 +2587,9 @@
|
|
|
2501
2587
|
"operationId": "getKillswitch",
|
|
2502
2588
|
"summary": "Get one killswitch",
|
|
2503
2589
|
"description": "Returns the killswitch metadata plus the latest published `value`/`switches`/`version` per env.\n\n**Use case:** Fetch the current state of one killswitch — e.g. to verify a trip propagated before declaring an incident mitigated.",
|
|
2504
|
-
"tags": [
|
|
2590
|
+
"tags": [
|
|
2591
|
+
"Killswitches"
|
|
2592
|
+
],
|
|
2505
2593
|
"parameters": [
|
|
2506
2594
|
{
|
|
2507
2595
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2577,7 +2665,9 @@
|
|
|
2577
2665
|
"operationId": "updateKillswitch",
|
|
2578
2666
|
"summary": "Update a killswitch",
|
|
2579
2667
|
"description": "Partial update applied to **every** env. Setting `value`/`switches` publishes a new version per env. Description-only patches don't bump versions.\n\nTo change a single switch on a single env, use `PUT /{id}/switch` instead.\n\n**Use cases**\n\n- **Trip everywhere** — `{ \"value\": true }`. Kills the feature across dev/stage/prod in one call.\n- **Untrip everywhere** — `{ \"value\": false }`.\n- **Replace switches** — send the full new map; per-key edits use `PUT /{id}/switch`.\n- **Update description** — metadata-only patches don't bump versions.",
|
|
2580
|
-
"tags": [
|
|
2668
|
+
"tags": [
|
|
2669
|
+
"Killswitches"
|
|
2670
|
+
],
|
|
2581
2671
|
"parameters": [
|
|
2582
2672
|
{
|
|
2583
2673
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2673,7 +2763,9 @@
|
|
|
2673
2763
|
"operationId": "deleteKillswitch",
|
|
2674
2764
|
"summary": "Delete a killswitch",
|
|
2675
2765
|
"description": "Soft-deletes the killswitch and rebuilds the project's flags KV blob so SDKs stop seeing it.\n\n**Use case:** Tear down a killswitch after the feature it protected has been removed.",
|
|
2676
|
-
"tags": [
|
|
2766
|
+
"tags": [
|
|
2767
|
+
"Killswitches"
|
|
2768
|
+
],
|
|
2677
2769
|
"parameters": [
|
|
2678
2770
|
{
|
|
2679
2771
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2728,7 +2820,9 @@
|
|
|
2728
2820
|
"operationId": "setKillswitchSwitch",
|
|
2729
2821
|
"summary": "Set one switch entry",
|
|
2730
2822
|
"description": "Sets or updates a single `switchKey` on a single `env`. Publishes one new version on that env only — other envs untouched.\n\nUse 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).\n\n**Use cases**\n\n- **Trip a region** — `{ \"env\": \"prod\", \"switchKey\": \"eu_region\", \"value\": true }`.\n- **Untrip without removing** — same payload with `value: false`. To remove the entry entirely use `DELETE /{id}/switch`.",
|
|
2731
|
-
"tags": [
|
|
2823
|
+
"tags": [
|
|
2824
|
+
"Killswitches"
|
|
2825
|
+
],
|
|
2732
2826
|
"parameters": [
|
|
2733
2827
|
{
|
|
2734
2828
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2814,7 +2908,9 @@
|
|
|
2814
2908
|
"operationId": "unsetKillswitchSwitch",
|
|
2815
2909
|
"summary": "Remove one switch entry",
|
|
2816
2910
|
"description": "Removes a single `switchKey` from the `switches` map on a single `env`. Publishes a new version on that env.\n\nReturns `{ removed: false }` if the entry didn't exist (idempotent no-op).\n\n**Use case:** Clean up a per-region override after the incident is resolved so the flat `value` governs again.",
|
|
2817
|
-
"tags": [
|
|
2911
|
+
"tags": [
|
|
2912
|
+
"Killswitches"
|
|
2913
|
+
],
|
|
2818
2914
|
"parameters": [
|
|
2819
2915
|
{
|
|
2820
2916
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2892,7 +2988,9 @@
|
|
|
2892
2988
|
"operationId": "listUniverses",
|
|
2893
2989
|
"summary": "List universes",
|
|
2894
2990
|
"description": "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.\n\n**Use case:** Snapshot every universe in the project — for example to audit which `unit_type` and `holdout_range` are in use before launching a new experiment.",
|
|
2895
|
-
"tags": [
|
|
2991
|
+
"tags": [
|
|
2992
|
+
"Universes"
|
|
2993
|
+
],
|
|
2896
2994
|
"parameters": [
|
|
2897
2995
|
{
|
|
2898
2996
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2918,7 +3016,10 @@
|
|
|
2918
3016
|
"id": "uni_01j7w8a1b2c3d4e5f6g7h8i9j0",
|
|
2919
3017
|
"name": "primary_users",
|
|
2920
3018
|
"unitType": "user_id",
|
|
2921
|
-
"holdoutRange": [
|
|
3019
|
+
"holdoutRange": [
|
|
3020
|
+
9500,
|
|
3021
|
+
9999
|
|
3022
|
+
],
|
|
2922
3023
|
"createdAt": "2026-04-12T10:14:08.000Z"
|
|
2923
3024
|
}
|
|
2924
3025
|
],
|
|
@@ -2951,7 +3052,9 @@
|
|
|
2951
3052
|
"operationId": "createUniverse",
|
|
2952
3053
|
"summary": "Create a universe",
|
|
2953
3054
|
"description": "Creates a new universe. Only `name` is required — `unit_type` defaults to `user_id` and `holdout_range` defaults to `null` (no holdout).\n\nReturns `409` if `name` already exists in the project. Returns `403` if you supply `holdout_range` on a plan below Pro.\n\n**Use cases**\n\n- **Default universe** — `{ \"name\": \"primary_users\" }`. Per-user randomisation, no holdout.\n- **Reserved holdout** — supply `holdout_range` to carve out a measurement slice excluded from all experiments.\n- **Account-level** — `unit_type: 'account_id'` so multi-seat accounts see one consistent variant.",
|
|
2954
|
-
"tags": [
|
|
3055
|
+
"tags": [
|
|
3056
|
+
"Universes"
|
|
3057
|
+
],
|
|
2955
3058
|
"parameters": [
|
|
2956
3059
|
{
|
|
2957
3060
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -2977,7 +3080,10 @@
|
|
|
2977
3080
|
"description": "Reserves buckets 9500–9999 (5% of callers) as the holdout. Pro plan or higher.",
|
|
2978
3081
|
"value": {
|
|
2979
3082
|
"name": "primary_users",
|
|
2980
|
-
"holdout_range": [
|
|
3083
|
+
"holdout_range": [
|
|
3084
|
+
9500,
|
|
3085
|
+
9999
|
|
3086
|
+
]
|
|
2981
3087
|
}
|
|
2982
3088
|
},
|
|
2983
3089
|
"accountLevel": {
|
|
@@ -3033,7 +3139,9 @@
|
|
|
3033
3139
|
"operationId": "updateUniverse",
|
|
3034
3140
|
"summary": "Update a universe",
|
|
3035
3141
|
"description": "Partial update. Only `holdout_range` is mutable — `name` and `unit_type` are immutable after create.\n\nPass `\"holdout_range\": null` to remove an existing holdout.\n\n**Use cases**\n\n- **Adjust holdout** — change the reserved measurement slice without recreating experiments.\n- **Remove holdout** — `{ \"holdout_range\": null }`.",
|
|
3036
|
-
"tags": [
|
|
3142
|
+
"tags": [
|
|
3143
|
+
"Universes"
|
|
3144
|
+
],
|
|
3037
3145
|
"parameters": [
|
|
3038
3146
|
{
|
|
3039
3147
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -3060,7 +3168,10 @@
|
|
|
3060
3168
|
"summary": "Set holdout — reserve 5%",
|
|
3061
3169
|
"description": "Reserve buckets 9500–9999 as the holdout. Pro plan or higher.",
|
|
3062
3170
|
"value": {
|
|
3063
|
-
"holdout_range": [
|
|
3171
|
+
"holdout_range": [
|
|
3172
|
+
9500,
|
|
3173
|
+
9999
|
|
3174
|
+
]
|
|
3064
3175
|
}
|
|
3065
3176
|
},
|
|
3066
3177
|
"removeHoldout": {
|
|
@@ -3112,7 +3223,9 @@
|
|
|
3112
3223
|
"operationId": "deleteUniverse",
|
|
3113
3224
|
"summary": "Delete a universe",
|
|
3114
3225
|
"description": "Soft-deletes the universe. Returns `409` if any non-archived experiment still references it — archive those experiments first.\n\n**Use case:** Tear down a universe after every experiment that used it has been archived.",
|
|
3115
|
-
"tags": [
|
|
3226
|
+
"tags": [
|
|
3227
|
+
"Universes"
|
|
3228
|
+
],
|
|
3116
3229
|
"parameters": [
|
|
3117
3230
|
{
|
|
3118
3231
|
"$ref": "#/components/parameters/ProjectId"
|
|
@@ -3167,7 +3280,9 @@
|
|
|
3167
3280
|
"schemas": {
|
|
3168
3281
|
"ErrorResponse": {
|
|
3169
3282
|
"type": "object",
|
|
3170
|
-
"required": [
|
|
3283
|
+
"required": [
|
|
3284
|
+
"error"
|
|
3285
|
+
],
|
|
3171
3286
|
"properties": {
|
|
3172
3287
|
"error": {
|
|
3173
3288
|
"type": "string",
|
|
@@ -3198,8 +3313,9 @@
|
|
|
3198
3313
|
},
|
|
3199
3314
|
"name": {
|
|
3200
3315
|
"type": "string",
|
|
3201
|
-
"
|
|
3202
|
-
"
|
|
3316
|
+
"maxLength": 128,
|
|
3317
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
3318
|
+
"description": "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."
|
|
3203
3319
|
},
|
|
3204
3320
|
"enabled": {
|
|
3205
3321
|
"anyOf": [
|
|
@@ -3242,15 +3358,25 @@
|
|
|
3242
3358
|
"lt",
|
|
3243
3359
|
"lte",
|
|
3244
3360
|
"contains",
|
|
3245
|
-
"regex"
|
|
3361
|
+
"regex",
|
|
3362
|
+
"semver_gt",
|
|
3363
|
+
"semver_gte",
|
|
3364
|
+
"semver_lt",
|
|
3365
|
+
"semver_lte",
|
|
3366
|
+
"gate_pass",
|
|
3367
|
+
"exp_in"
|
|
3246
3368
|
],
|
|
3247
|
-
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string)."
|
|
3369
|
+
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
|
|
3248
3370
|
},
|
|
3249
3371
|
"value": {
|
|
3250
|
-
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains
|
|
3372
|
+
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `\"$holdout\"` / `\"$any\"` for `exp_in`."
|
|
3251
3373
|
}
|
|
3252
3374
|
},
|
|
3253
|
-
"required": [
|
|
3375
|
+
"required": [
|
|
3376
|
+
"attr",
|
|
3377
|
+
"op",
|
|
3378
|
+
"value"
|
|
3379
|
+
],
|
|
3254
3380
|
"additionalProperties": false,
|
|
3255
3381
|
"description": "Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic."
|
|
3256
3382
|
}
|
|
@@ -3323,7 +3449,7 @@
|
|
|
3323
3449
|
"id": {
|
|
3324
3450
|
"type": "string",
|
|
3325
3451
|
"minLength": 1,
|
|
3326
|
-
"description": "Client-supplied stable id for the stack entry (used for React keys, audit diffs)."
|
|
3452
|
+
"description": "Client-supplied stable id for the stack entry (used for React keys, audit diffs, and as the default per-condition rollout salt)."
|
|
3327
3453
|
},
|
|
3328
3454
|
"type": {
|
|
3329
3455
|
"type": "string",
|
|
@@ -3348,7 +3474,10 @@
|
|
|
3348
3474
|
"pass": {
|
|
3349
3475
|
"description": "Combinator across `rules`. `all` = AND (default), `any` = OR.",
|
|
3350
3476
|
"type": "string",
|
|
3351
|
-
"enum": [
|
|
3477
|
+
"enum": [
|
|
3478
|
+
"all",
|
|
3479
|
+
"any"
|
|
3480
|
+
]
|
|
3352
3481
|
},
|
|
3353
3482
|
"rules": {
|
|
3354
3483
|
"default": [],
|
|
@@ -3374,27 +3503,92 @@
|
|
|
3374
3503
|
"lt",
|
|
3375
3504
|
"lte",
|
|
3376
3505
|
"contains",
|
|
3377
|
-
"regex"
|
|
3506
|
+
"regex",
|
|
3507
|
+
"semver_gt",
|
|
3508
|
+
"semver_gte",
|
|
3509
|
+
"semver_lt",
|
|
3510
|
+
"semver_lte",
|
|
3511
|
+
"gate_pass",
|
|
3512
|
+
"exp_in"
|
|
3378
3513
|
],
|
|
3379
|
-
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string)."
|
|
3514
|
+
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
|
|
3380
3515
|
},
|
|
3381
3516
|
"value": {
|
|
3382
|
-
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains
|
|
3517
|
+
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `\"$holdout\"` / `\"$any\"` for `exp_in`."
|
|
3383
3518
|
}
|
|
3384
3519
|
},
|
|
3385
|
-
"required": [
|
|
3520
|
+
"required": [
|
|
3521
|
+
"attr",
|
|
3522
|
+
"op",
|
|
3523
|
+
"value"
|
|
3524
|
+
],
|
|
3386
3525
|
"additionalProperties": false,
|
|
3387
3526
|
"description": "Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic."
|
|
3388
3527
|
}
|
|
3389
3528
|
},
|
|
3529
|
+
"rolloutPct": {
|
|
3530
|
+
"description": "Per-condition rollout in basis points. After the rules match, the caller is bucketed at this %; in-bucket → gate `true`, otherwise fall through to the next entry. Absent ⇒ 10000 (100%, every matching caller passes).",
|
|
3531
|
+
"type": "integer",
|
|
3532
|
+
"minimum": 0,
|
|
3533
|
+
"maximum": 10000
|
|
3534
|
+
},
|
|
3535
|
+
"bucketBy": {
|
|
3536
|
+
"description": "Attribute used to hash the caller into the per-condition bucket. Default `userID`.",
|
|
3537
|
+
"type": "string"
|
|
3538
|
+
},
|
|
3539
|
+
"salt": {
|
|
3540
|
+
"description": "Per-condition hash salt. Defaults to the entry `id`, then the gate salt.",
|
|
3541
|
+
"type": "string"
|
|
3542
|
+
},
|
|
3543
|
+
"ramp": {
|
|
3544
|
+
"type": "object",
|
|
3545
|
+
"properties": {
|
|
3546
|
+
"from": {
|
|
3547
|
+
"type": "integer",
|
|
3548
|
+
"minimum": 0,
|
|
3549
|
+
"maximum": 10000,
|
|
3550
|
+
"description": "Start of the ramp in basis points (0–10000)."
|
|
3551
|
+
},
|
|
3552
|
+
"to": {
|
|
3553
|
+
"type": "integer",
|
|
3554
|
+
"minimum": 0,
|
|
3555
|
+
"maximum": 10000,
|
|
3556
|
+
"description": "End of the ramp in basis points (0–10000)."
|
|
3557
|
+
},
|
|
3558
|
+
"startAt": {
|
|
3559
|
+
"type": "integer",
|
|
3560
|
+
"minimum": 0,
|
|
3561
|
+
"maximum": 9007199254740991,
|
|
3562
|
+
"description": "Ramp start, epoch milliseconds (UTC)."
|
|
3563
|
+
},
|
|
3564
|
+
"durationMs": {
|
|
3565
|
+
"type": "integer",
|
|
3566
|
+
"exclusiveMinimum": 0,
|
|
3567
|
+
"maximum": 9007199254740991,
|
|
3568
|
+
"description": "Ramp length in milliseconds."
|
|
3569
|
+
}
|
|
3570
|
+
},
|
|
3571
|
+
"required": [
|
|
3572
|
+
"from",
|
|
3573
|
+
"to",
|
|
3574
|
+
"startAt",
|
|
3575
|
+
"durationMs"
|
|
3576
|
+
],
|
|
3577
|
+
"additionalProperties": false,
|
|
3578
|
+
"description": "Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present."
|
|
3579
|
+
},
|
|
3390
3580
|
"locked": {
|
|
3391
3581
|
"description": "If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).",
|
|
3392
3582
|
"type": "boolean"
|
|
3393
3583
|
}
|
|
3394
3584
|
},
|
|
3395
|
-
"required": [
|
|
3585
|
+
"required": [
|
|
3586
|
+
"id",
|
|
3587
|
+
"type",
|
|
3588
|
+
"rules"
|
|
3589
|
+
],
|
|
3396
3590
|
"additionalProperties": false,
|
|
3397
|
-
"description": "Rule-based sub-gate. When
|
|
3591
|
+
"description": "Rule-based sub-gate. When the rules match and the caller falls in the per-condition rollout bucket, evaluation short-circuits and the gate returns `true`; otherwise it falls through to the next entry."
|
|
3398
3592
|
},
|
|
3399
3593
|
{
|
|
3400
3594
|
"type": "object",
|
|
@@ -3438,14 +3632,55 @@
|
|
|
3438
3632
|
"description": "Per-entry hash salt. Defaults to the gate's salt. Set explicitly to keep two rollouts independent or correlated across gates.",
|
|
3439
3633
|
"type": "string"
|
|
3440
3634
|
},
|
|
3635
|
+
"ramp": {
|
|
3636
|
+
"type": "object",
|
|
3637
|
+
"properties": {
|
|
3638
|
+
"from": {
|
|
3639
|
+
"type": "integer",
|
|
3640
|
+
"minimum": 0,
|
|
3641
|
+
"maximum": 10000,
|
|
3642
|
+
"description": "Start of the ramp in basis points (0–10000)."
|
|
3643
|
+
},
|
|
3644
|
+
"to": {
|
|
3645
|
+
"type": "integer",
|
|
3646
|
+
"minimum": 0,
|
|
3647
|
+
"maximum": 10000,
|
|
3648
|
+
"description": "End of the ramp in basis points (0–10000)."
|
|
3649
|
+
},
|
|
3650
|
+
"startAt": {
|
|
3651
|
+
"type": "integer",
|
|
3652
|
+
"minimum": 0,
|
|
3653
|
+
"maximum": 9007199254740991,
|
|
3654
|
+
"description": "Ramp start, epoch milliseconds (UTC)."
|
|
3655
|
+
},
|
|
3656
|
+
"durationMs": {
|
|
3657
|
+
"type": "integer",
|
|
3658
|
+
"exclusiveMinimum": 0,
|
|
3659
|
+
"maximum": 9007199254740991,
|
|
3660
|
+
"description": "Ramp length in milliseconds."
|
|
3661
|
+
}
|
|
3662
|
+
},
|
|
3663
|
+
"required": [
|
|
3664
|
+
"from",
|
|
3665
|
+
"to",
|
|
3666
|
+
"startAt",
|
|
3667
|
+
"durationMs"
|
|
3668
|
+
],
|
|
3669
|
+
"additionalProperties": false,
|
|
3670
|
+
"description": "Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present."
|
|
3671
|
+
},
|
|
3441
3672
|
"locked": {
|
|
3442
3673
|
"description": "If `true`, dashboard hides edit controls.",
|
|
3443
3674
|
"type": "boolean"
|
|
3444
3675
|
}
|
|
3445
3676
|
},
|
|
3446
|
-
"required": [
|
|
3677
|
+
"required": [
|
|
3678
|
+
"id",
|
|
3679
|
+
"type",
|
|
3680
|
+
"rolloutPct"
|
|
3681
|
+
],
|
|
3447
3682
|
"additionalProperties": false,
|
|
3448
|
-
"description": "Percentage-rollout sub-gate. Hashes `bucketBy` (default `userID`) with `salt` and returns `true` for `rolloutPct/10000` fraction of callers."
|
|
3683
|
+
"description": "Percentage-rollout sub-gate. Hashes `bucketBy` (default `userID`) with `salt` and returns `true` for `rolloutPct/10000` fraction of callers (or the ramp's effective % when `ramp` is set)."
|
|
3449
3684
|
}
|
|
3450
3685
|
],
|
|
3451
3686
|
"description": "One entry in the ordered gatekeeper stack. Evaluated top-to-bottom; first matching entry decides. Mix `condition` and `rollout` entries to express `internal-only` + `1% beta` + `50% public` in a single gate."
|
|
@@ -3461,7 +3696,13 @@
|
|
|
3461
3696
|
"description": "ISO-8601 timestamp of last mutation."
|
|
3462
3697
|
}
|
|
3463
3698
|
},
|
|
3464
|
-
"required": [
|
|
3699
|
+
"required": [
|
|
3700
|
+
"id",
|
|
3701
|
+
"name",
|
|
3702
|
+
"enabled",
|
|
3703
|
+
"rolloutPct",
|
|
3704
|
+
"updatedAt"
|
|
3705
|
+
],
|
|
3465
3706
|
"additionalProperties": false
|
|
3466
3707
|
}
|
|
3467
3708
|
},
|
|
@@ -3476,7 +3717,10 @@
|
|
|
3476
3717
|
]
|
|
3477
3718
|
}
|
|
3478
3719
|
},
|
|
3479
|
-
"required": [
|
|
3720
|
+
"required": [
|
|
3721
|
+
"data",
|
|
3722
|
+
"next_cursor"
|
|
3723
|
+
],
|
|
3480
3724
|
"additionalProperties": false
|
|
3481
3725
|
},
|
|
3482
3726
|
"CreateGateRequest": {
|
|
@@ -3484,8 +3728,9 @@
|
|
|
3484
3728
|
"properties": {
|
|
3485
3729
|
"name": {
|
|
3486
3730
|
"type": "string",
|
|
3487
|
-
"
|
|
3488
|
-
"
|
|
3731
|
+
"maxLength": 128,
|
|
3732
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
3733
|
+
"description": "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."
|
|
3489
3734
|
},
|
|
3490
3735
|
"enabled": {
|
|
3491
3736
|
"default": true,
|
|
@@ -3494,11 +3739,17 @@
|
|
|
3494
3739
|
},
|
|
3495
3740
|
"rollout_pct": {
|
|
3496
3741
|
"default": 0,
|
|
3497
|
-
"description": "Initial rollout in basis points (0–10000 = 0%–100%). Use `0` to create the gate dark and ramp via PATCH after deploy validation.",
|
|
3742
|
+
"description": "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.",
|
|
3498
3743
|
"type": "integer",
|
|
3499
3744
|
"minimum": 0,
|
|
3500
3745
|
"maximum": 10000
|
|
3501
3746
|
},
|
|
3747
|
+
"rollout_percent": {
|
|
3748
|
+
"description": "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.",
|
|
3749
|
+
"type": "number",
|
|
3750
|
+
"minimum": 0,
|
|
3751
|
+
"maximum": 100
|
|
3752
|
+
},
|
|
3502
3753
|
"rules": {
|
|
3503
3754
|
"default": [],
|
|
3504
3755
|
"description": "Targeting predicates. AND-combined. If non-empty, the gate returns `true` only for callers that satisfy every rule **and** fall under `rollout_pct`.",
|
|
@@ -3523,15 +3774,25 @@
|
|
|
3523
3774
|
"lt",
|
|
3524
3775
|
"lte",
|
|
3525
3776
|
"contains",
|
|
3526
|
-
"regex"
|
|
3777
|
+
"regex",
|
|
3778
|
+
"semver_gt",
|
|
3779
|
+
"semver_gte",
|
|
3780
|
+
"semver_lt",
|
|
3781
|
+
"semver_lte",
|
|
3782
|
+
"gate_pass",
|
|
3783
|
+
"exp_in"
|
|
3527
3784
|
],
|
|
3528
|
-
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string)."
|
|
3785
|
+
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
|
|
3529
3786
|
},
|
|
3530
3787
|
"value": {
|
|
3531
|
-
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains
|
|
3788
|
+
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `\"$holdout\"` / `\"$any\"` for `exp_in`."
|
|
3532
3789
|
}
|
|
3533
3790
|
},
|
|
3534
|
-
"required": [
|
|
3791
|
+
"required": [
|
|
3792
|
+
"attr",
|
|
3793
|
+
"op",
|
|
3794
|
+
"value"
|
|
3795
|
+
],
|
|
3535
3796
|
"additionalProperties": false,
|
|
3536
3797
|
"description": "Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic."
|
|
3537
3798
|
}
|
|
@@ -3555,7 +3816,7 @@
|
|
|
3555
3816
|
"id": {
|
|
3556
3817
|
"type": "string",
|
|
3557
3818
|
"minLength": 1,
|
|
3558
|
-
"description": "Client-supplied stable id for the stack entry (used for React keys, audit diffs)."
|
|
3819
|
+
"description": "Client-supplied stable id for the stack entry (used for React keys, audit diffs, and as the default per-condition rollout salt)."
|
|
3559
3820
|
},
|
|
3560
3821
|
"type": {
|
|
3561
3822
|
"type": "string",
|
|
@@ -3580,7 +3841,10 @@
|
|
|
3580
3841
|
"pass": {
|
|
3581
3842
|
"description": "Combinator across `rules`. `all` = AND (default), `any` = OR.",
|
|
3582
3843
|
"type": "string",
|
|
3583
|
-
"enum": [
|
|
3844
|
+
"enum": [
|
|
3845
|
+
"all",
|
|
3846
|
+
"any"
|
|
3847
|
+
]
|
|
3584
3848
|
},
|
|
3585
3849
|
"rules": {
|
|
3586
3850
|
"default": [],
|
|
@@ -3606,27 +3870,92 @@
|
|
|
3606
3870
|
"lt",
|
|
3607
3871
|
"lte",
|
|
3608
3872
|
"contains",
|
|
3609
|
-
"regex"
|
|
3873
|
+
"regex",
|
|
3874
|
+
"semver_gt",
|
|
3875
|
+
"semver_gte",
|
|
3876
|
+
"semver_lt",
|
|
3877
|
+
"semver_lte",
|
|
3878
|
+
"gate_pass",
|
|
3879
|
+
"exp_in"
|
|
3610
3880
|
],
|
|
3611
|
-
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string)."
|
|
3881
|
+
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
|
|
3612
3882
|
},
|
|
3613
3883
|
"value": {
|
|
3614
|
-
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains
|
|
3884
|
+
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `\"$holdout\"` / `\"$any\"` for `exp_in`."
|
|
3615
3885
|
}
|
|
3616
3886
|
},
|
|
3617
|
-
"required": [
|
|
3887
|
+
"required": [
|
|
3888
|
+
"attr",
|
|
3889
|
+
"op",
|
|
3890
|
+
"value"
|
|
3891
|
+
],
|
|
3618
3892
|
"additionalProperties": false,
|
|
3619
3893
|
"description": "Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic."
|
|
3620
3894
|
}
|
|
3621
3895
|
},
|
|
3896
|
+
"rolloutPct": {
|
|
3897
|
+
"description": "Per-condition rollout in basis points. After the rules match, the caller is bucketed at this %; in-bucket → gate `true`, otherwise fall through to the next entry. Absent ⇒ 10000 (100%, every matching caller passes).",
|
|
3898
|
+
"type": "integer",
|
|
3899
|
+
"minimum": 0,
|
|
3900
|
+
"maximum": 10000
|
|
3901
|
+
},
|
|
3902
|
+
"bucketBy": {
|
|
3903
|
+
"description": "Attribute used to hash the caller into the per-condition bucket. Default `userID`.",
|
|
3904
|
+
"type": "string"
|
|
3905
|
+
},
|
|
3906
|
+
"salt": {
|
|
3907
|
+
"description": "Per-condition hash salt. Defaults to the entry `id`, then the gate salt.",
|
|
3908
|
+
"type": "string"
|
|
3909
|
+
},
|
|
3910
|
+
"ramp": {
|
|
3911
|
+
"type": "object",
|
|
3912
|
+
"properties": {
|
|
3913
|
+
"from": {
|
|
3914
|
+
"type": "integer",
|
|
3915
|
+
"minimum": 0,
|
|
3916
|
+
"maximum": 10000,
|
|
3917
|
+
"description": "Start of the ramp in basis points (0–10000)."
|
|
3918
|
+
},
|
|
3919
|
+
"to": {
|
|
3920
|
+
"type": "integer",
|
|
3921
|
+
"minimum": 0,
|
|
3922
|
+
"maximum": 10000,
|
|
3923
|
+
"description": "End of the ramp in basis points (0–10000)."
|
|
3924
|
+
},
|
|
3925
|
+
"startAt": {
|
|
3926
|
+
"type": "integer",
|
|
3927
|
+
"minimum": 0,
|
|
3928
|
+
"maximum": 9007199254740991,
|
|
3929
|
+
"description": "Ramp start, epoch milliseconds (UTC)."
|
|
3930
|
+
},
|
|
3931
|
+
"durationMs": {
|
|
3932
|
+
"type": "integer",
|
|
3933
|
+
"exclusiveMinimum": 0,
|
|
3934
|
+
"maximum": 9007199254740991,
|
|
3935
|
+
"description": "Ramp length in milliseconds."
|
|
3936
|
+
}
|
|
3937
|
+
},
|
|
3938
|
+
"required": [
|
|
3939
|
+
"from",
|
|
3940
|
+
"to",
|
|
3941
|
+
"startAt",
|
|
3942
|
+
"durationMs"
|
|
3943
|
+
],
|
|
3944
|
+
"additionalProperties": false,
|
|
3945
|
+
"description": "Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present."
|
|
3946
|
+
},
|
|
3622
3947
|
"locked": {
|
|
3623
3948
|
"description": "If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).",
|
|
3624
3949
|
"type": "boolean"
|
|
3625
3950
|
}
|
|
3626
3951
|
},
|
|
3627
|
-
"required": [
|
|
3952
|
+
"required": [
|
|
3953
|
+
"id",
|
|
3954
|
+
"type",
|
|
3955
|
+
"rules"
|
|
3956
|
+
],
|
|
3628
3957
|
"additionalProperties": false,
|
|
3629
|
-
"description": "Rule-based sub-gate. When
|
|
3958
|
+
"description": "Rule-based sub-gate. When the rules match and the caller falls in the per-condition rollout bucket, evaluation short-circuits and the gate returns `true`; otherwise it falls through to the next entry."
|
|
3630
3959
|
},
|
|
3631
3960
|
{
|
|
3632
3961
|
"type": "object",
|
|
@@ -3670,14 +3999,55 @@
|
|
|
3670
3999
|
"description": "Per-entry hash salt. Defaults to the gate's salt. Set explicitly to keep two rollouts independent or correlated across gates.",
|
|
3671
4000
|
"type": "string"
|
|
3672
4001
|
},
|
|
4002
|
+
"ramp": {
|
|
4003
|
+
"type": "object",
|
|
4004
|
+
"properties": {
|
|
4005
|
+
"from": {
|
|
4006
|
+
"type": "integer",
|
|
4007
|
+
"minimum": 0,
|
|
4008
|
+
"maximum": 10000,
|
|
4009
|
+
"description": "Start of the ramp in basis points (0–10000)."
|
|
4010
|
+
},
|
|
4011
|
+
"to": {
|
|
4012
|
+
"type": "integer",
|
|
4013
|
+
"minimum": 0,
|
|
4014
|
+
"maximum": 10000,
|
|
4015
|
+
"description": "End of the ramp in basis points (0–10000)."
|
|
4016
|
+
},
|
|
4017
|
+
"startAt": {
|
|
4018
|
+
"type": "integer",
|
|
4019
|
+
"minimum": 0,
|
|
4020
|
+
"maximum": 9007199254740991,
|
|
4021
|
+
"description": "Ramp start, epoch milliseconds (UTC)."
|
|
4022
|
+
},
|
|
4023
|
+
"durationMs": {
|
|
4024
|
+
"type": "integer",
|
|
4025
|
+
"exclusiveMinimum": 0,
|
|
4026
|
+
"maximum": 9007199254740991,
|
|
4027
|
+
"description": "Ramp length in milliseconds."
|
|
4028
|
+
}
|
|
4029
|
+
},
|
|
4030
|
+
"required": [
|
|
4031
|
+
"from",
|
|
4032
|
+
"to",
|
|
4033
|
+
"startAt",
|
|
4034
|
+
"durationMs"
|
|
4035
|
+
],
|
|
4036
|
+
"additionalProperties": false,
|
|
4037
|
+
"description": "Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present."
|
|
4038
|
+
},
|
|
3673
4039
|
"locked": {
|
|
3674
4040
|
"description": "If `true`, dashboard hides edit controls.",
|
|
3675
4041
|
"type": "boolean"
|
|
3676
4042
|
}
|
|
3677
4043
|
},
|
|
3678
|
-
"required": [
|
|
4044
|
+
"required": [
|
|
4045
|
+
"id",
|
|
4046
|
+
"type",
|
|
4047
|
+
"rolloutPct"
|
|
4048
|
+
],
|
|
3679
4049
|
"additionalProperties": false,
|
|
3680
|
-
"description": "Percentage-rollout sub-gate. Hashes `bucketBy` (default `userID`) with `salt` and returns `true` for `rolloutPct/10000` fraction of callers."
|
|
4050
|
+
"description": "Percentage-rollout sub-gate. Hashes `bucketBy` (default `userID`) with `salt` and returns `true` for `rolloutPct/10000` fraction of callers (or the ramp's effective % when `ramp` is set)."
|
|
3681
4051
|
}
|
|
3682
4052
|
],
|
|
3683
4053
|
"description": "One entry in the ordered gatekeeper stack. Evaluated top-to-bottom; first matching entry decides. Mix `condition` and `rollout` entries to express `internal-only` + `1% beta` + `50% public` in a single gate."
|
|
@@ -3699,9 +4069,17 @@
|
|
|
3699
4069
|
"maxLength": 2000
|
|
3700
4070
|
},
|
|
3701
4071
|
"folder": {
|
|
3702
|
-
"description": "
|
|
3703
|
-
"
|
|
3704
|
-
|
|
4072
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
4073
|
+
"anyOf": [
|
|
4074
|
+
{
|
|
4075
|
+
"type": "string",
|
|
4076
|
+
"maxLength": 256,
|
|
4077
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
4078
|
+
},
|
|
4079
|
+
{
|
|
4080
|
+
"type": "null"
|
|
4081
|
+
}
|
|
4082
|
+
]
|
|
3705
4083
|
},
|
|
3706
4084
|
"group": {
|
|
3707
4085
|
"description": "Group label for dashboard organisation (e.g. team or product area).",
|
|
@@ -3714,7 +4092,12 @@
|
|
|
3714
4092
|
"maxLength": 190
|
|
3715
4093
|
}
|
|
3716
4094
|
},
|
|
3717
|
-
"required": [
|
|
4095
|
+
"required": [
|
|
4096
|
+
"name",
|
|
4097
|
+
"enabled",
|
|
4098
|
+
"rollout_pct",
|
|
4099
|
+
"rules"
|
|
4100
|
+
],
|
|
3718
4101
|
"additionalProperties": false,
|
|
3719
4102
|
"description": "Body for `POST /api/admin/gates`. At minimum supply `name`; everything else has sensible defaults."
|
|
3720
4103
|
},
|
|
@@ -3727,22 +4110,32 @@
|
|
|
3727
4110
|
},
|
|
3728
4111
|
"name": {
|
|
3729
4112
|
"type": "string",
|
|
3730
|
-
"
|
|
3731
|
-
"
|
|
4113
|
+
"maxLength": 128,
|
|
4114
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
4115
|
+
"description": "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."
|
|
3732
4116
|
}
|
|
3733
4117
|
},
|
|
3734
|
-
"required": [
|
|
4118
|
+
"required": [
|
|
4119
|
+
"id",
|
|
4120
|
+
"name"
|
|
4121
|
+
],
|
|
3735
4122
|
"additionalProperties": false
|
|
3736
4123
|
},
|
|
3737
4124
|
"UpdateGateRequest": {
|
|
3738
4125
|
"type": "object",
|
|
3739
4126
|
"properties": {
|
|
3740
4127
|
"rollout_pct": {
|
|
3741
|
-
"description": "New rollout in basis points (0–10000 = 0%–100%). Omit to leave unchanged.",
|
|
4128
|
+
"description": "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.",
|
|
3742
4129
|
"type": "integer",
|
|
3743
4130
|
"minimum": 0,
|
|
3744
4131
|
"maximum": 10000
|
|
3745
4132
|
},
|
|
4133
|
+
"rollout_percent": {
|
|
4134
|
+
"description": "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.",
|
|
4135
|
+
"type": "number",
|
|
4136
|
+
"minimum": 0,
|
|
4137
|
+
"maximum": 100
|
|
4138
|
+
},
|
|
3746
4139
|
"rules": {
|
|
3747
4140
|
"description": "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']`).",
|
|
3748
4141
|
"type": "array",
|
|
@@ -3766,15 +4159,25 @@
|
|
|
3766
4159
|
"lt",
|
|
3767
4160
|
"lte",
|
|
3768
4161
|
"contains",
|
|
3769
|
-
"regex"
|
|
4162
|
+
"regex",
|
|
4163
|
+
"semver_gt",
|
|
4164
|
+
"semver_gte",
|
|
4165
|
+
"semver_lt",
|
|
4166
|
+
"semver_lte",
|
|
4167
|
+
"gate_pass",
|
|
4168
|
+
"exp_in"
|
|
3770
4169
|
],
|
|
3771
|
-
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string)."
|
|
4170
|
+
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
|
|
3772
4171
|
},
|
|
3773
4172
|
"value": {
|
|
3774
|
-
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains
|
|
4173
|
+
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `\"$holdout\"` / `\"$any\"` for `exp_in`."
|
|
3775
4174
|
}
|
|
3776
4175
|
},
|
|
3777
|
-
"required": [
|
|
4176
|
+
"required": [
|
|
4177
|
+
"attr",
|
|
4178
|
+
"op",
|
|
4179
|
+
"value"
|
|
4180
|
+
],
|
|
3778
4181
|
"additionalProperties": false,
|
|
3779
4182
|
"description": "Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic."
|
|
3780
4183
|
}
|
|
@@ -3796,7 +4199,7 @@
|
|
|
3796
4199
|
"id": {
|
|
3797
4200
|
"type": "string",
|
|
3798
4201
|
"minLength": 1,
|
|
3799
|
-
"description": "Client-supplied stable id for the stack entry (used for React keys, audit diffs)."
|
|
4202
|
+
"description": "Client-supplied stable id for the stack entry (used for React keys, audit diffs, and as the default per-condition rollout salt)."
|
|
3800
4203
|
},
|
|
3801
4204
|
"type": {
|
|
3802
4205
|
"type": "string",
|
|
@@ -3821,7 +4224,10 @@
|
|
|
3821
4224
|
"pass": {
|
|
3822
4225
|
"description": "Combinator across `rules`. `all` = AND (default), `any` = OR.",
|
|
3823
4226
|
"type": "string",
|
|
3824
|
-
"enum": [
|
|
4227
|
+
"enum": [
|
|
4228
|
+
"all",
|
|
4229
|
+
"any"
|
|
4230
|
+
]
|
|
3825
4231
|
},
|
|
3826
4232
|
"rules": {
|
|
3827
4233
|
"default": [],
|
|
@@ -3847,27 +4253,92 @@
|
|
|
3847
4253
|
"lt",
|
|
3848
4254
|
"lte",
|
|
3849
4255
|
"contains",
|
|
3850
|
-
"regex"
|
|
4256
|
+
"regex",
|
|
4257
|
+
"semver_gt",
|
|
4258
|
+
"semver_gte",
|
|
4259
|
+
"semver_lt",
|
|
4260
|
+
"semver_lte",
|
|
4261
|
+
"gate_pass",
|
|
4262
|
+
"exp_in"
|
|
3851
4263
|
],
|
|
3852
|
-
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string)."
|
|
4264
|
+
"description": "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
|
|
3853
4265
|
},
|
|
3854
4266
|
"value": {
|
|
3855
|
-
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains
|
|
4267
|
+
"description": "Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `\"$holdout\"` / `\"$any\"` for `exp_in`."
|
|
3856
4268
|
}
|
|
3857
4269
|
},
|
|
3858
|
-
"required": [
|
|
4270
|
+
"required": [
|
|
4271
|
+
"attr",
|
|
4272
|
+
"op",
|
|
4273
|
+
"value"
|
|
4274
|
+
],
|
|
3859
4275
|
"additionalProperties": false,
|
|
3860
4276
|
"description": "Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic."
|
|
3861
4277
|
}
|
|
3862
4278
|
},
|
|
4279
|
+
"rolloutPct": {
|
|
4280
|
+
"description": "Per-condition rollout in basis points. After the rules match, the caller is bucketed at this %; in-bucket → gate `true`, otherwise fall through to the next entry. Absent ⇒ 10000 (100%, every matching caller passes).",
|
|
4281
|
+
"type": "integer",
|
|
4282
|
+
"minimum": 0,
|
|
4283
|
+
"maximum": 10000
|
|
4284
|
+
},
|
|
4285
|
+
"bucketBy": {
|
|
4286
|
+
"description": "Attribute used to hash the caller into the per-condition bucket. Default `userID`.",
|
|
4287
|
+
"type": "string"
|
|
4288
|
+
},
|
|
4289
|
+
"salt": {
|
|
4290
|
+
"description": "Per-condition hash salt. Defaults to the entry `id`, then the gate salt.",
|
|
4291
|
+
"type": "string"
|
|
4292
|
+
},
|
|
4293
|
+
"ramp": {
|
|
4294
|
+
"type": "object",
|
|
4295
|
+
"properties": {
|
|
4296
|
+
"from": {
|
|
4297
|
+
"type": "integer",
|
|
4298
|
+
"minimum": 0,
|
|
4299
|
+
"maximum": 10000,
|
|
4300
|
+
"description": "Start of the ramp in basis points (0–10000)."
|
|
4301
|
+
},
|
|
4302
|
+
"to": {
|
|
4303
|
+
"type": "integer",
|
|
4304
|
+
"minimum": 0,
|
|
4305
|
+
"maximum": 10000,
|
|
4306
|
+
"description": "End of the ramp in basis points (0–10000)."
|
|
4307
|
+
},
|
|
4308
|
+
"startAt": {
|
|
4309
|
+
"type": "integer",
|
|
4310
|
+
"minimum": 0,
|
|
4311
|
+
"maximum": 9007199254740991,
|
|
4312
|
+
"description": "Ramp start, epoch milliseconds (UTC)."
|
|
4313
|
+
},
|
|
4314
|
+
"durationMs": {
|
|
4315
|
+
"type": "integer",
|
|
4316
|
+
"exclusiveMinimum": 0,
|
|
4317
|
+
"maximum": 9007199254740991,
|
|
4318
|
+
"description": "Ramp length in milliseconds."
|
|
4319
|
+
}
|
|
4320
|
+
},
|
|
4321
|
+
"required": [
|
|
4322
|
+
"from",
|
|
4323
|
+
"to",
|
|
4324
|
+
"startAt",
|
|
4325
|
+
"durationMs"
|
|
4326
|
+
],
|
|
4327
|
+
"additionalProperties": false,
|
|
4328
|
+
"description": "Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present."
|
|
4329
|
+
},
|
|
3863
4330
|
"locked": {
|
|
3864
4331
|
"description": "If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).",
|
|
3865
4332
|
"type": "boolean"
|
|
3866
4333
|
}
|
|
3867
4334
|
},
|
|
3868
|
-
"required": [
|
|
4335
|
+
"required": [
|
|
4336
|
+
"id",
|
|
4337
|
+
"type",
|
|
4338
|
+
"rules"
|
|
4339
|
+
],
|
|
3869
4340
|
"additionalProperties": false,
|
|
3870
|
-
"description": "Rule-based sub-gate. When
|
|
4341
|
+
"description": "Rule-based sub-gate. When the rules match and the caller falls in the per-condition rollout bucket, evaluation short-circuits and the gate returns `true`; otherwise it falls through to the next entry."
|
|
3871
4342
|
},
|
|
3872
4343
|
{
|
|
3873
4344
|
"type": "object",
|
|
@@ -3911,14 +4382,55 @@
|
|
|
3911
4382
|
"description": "Per-entry hash salt. Defaults to the gate's salt. Set explicitly to keep two rollouts independent or correlated across gates.",
|
|
3912
4383
|
"type": "string"
|
|
3913
4384
|
},
|
|
4385
|
+
"ramp": {
|
|
4386
|
+
"type": "object",
|
|
4387
|
+
"properties": {
|
|
4388
|
+
"from": {
|
|
4389
|
+
"type": "integer",
|
|
4390
|
+
"minimum": 0,
|
|
4391
|
+
"maximum": 10000,
|
|
4392
|
+
"description": "Start of the ramp in basis points (0–10000)."
|
|
4393
|
+
},
|
|
4394
|
+
"to": {
|
|
4395
|
+
"type": "integer",
|
|
4396
|
+
"minimum": 0,
|
|
4397
|
+
"maximum": 10000,
|
|
4398
|
+
"description": "End of the ramp in basis points (0–10000)."
|
|
4399
|
+
},
|
|
4400
|
+
"startAt": {
|
|
4401
|
+
"type": "integer",
|
|
4402
|
+
"minimum": 0,
|
|
4403
|
+
"maximum": 9007199254740991,
|
|
4404
|
+
"description": "Ramp start, epoch milliseconds (UTC)."
|
|
4405
|
+
},
|
|
4406
|
+
"durationMs": {
|
|
4407
|
+
"type": "integer",
|
|
4408
|
+
"exclusiveMinimum": 0,
|
|
4409
|
+
"maximum": 9007199254740991,
|
|
4410
|
+
"description": "Ramp length in milliseconds."
|
|
4411
|
+
}
|
|
4412
|
+
},
|
|
4413
|
+
"required": [
|
|
4414
|
+
"from",
|
|
4415
|
+
"to",
|
|
4416
|
+
"startAt",
|
|
4417
|
+
"durationMs"
|
|
4418
|
+
],
|
|
4419
|
+
"additionalProperties": false,
|
|
4420
|
+
"description": "Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present."
|
|
4421
|
+
},
|
|
3914
4422
|
"locked": {
|
|
3915
4423
|
"description": "If `true`, dashboard hides edit controls.",
|
|
3916
4424
|
"type": "boolean"
|
|
3917
4425
|
}
|
|
3918
4426
|
},
|
|
3919
|
-
"required": [
|
|
4427
|
+
"required": [
|
|
4428
|
+
"id",
|
|
4429
|
+
"type",
|
|
4430
|
+
"rolloutPct"
|
|
4431
|
+
],
|
|
3920
4432
|
"additionalProperties": false,
|
|
3921
|
-
"description": "Percentage-rollout sub-gate. Hashes `bucketBy` (default `userID`) with `salt` and returns `true` for `rolloutPct/10000` fraction of callers."
|
|
4433
|
+
"description": "Percentage-rollout sub-gate. Hashes `bucketBy` (default `userID`) with `salt` and returns `true` for `rolloutPct/10000` fraction of callers (or the ramp's effective % when `ramp` is set)."
|
|
3922
4434
|
}
|
|
3923
4435
|
],
|
|
3924
4436
|
"description": "One entry in the ordered gatekeeper stack. Evaluated top-to-bottom; first matching entry decides. Mix `condition` and `rollout` entries to express `internal-only` + `1% beta` + `50% public` in a single gate."
|
|
@@ -3940,9 +4452,17 @@
|
|
|
3940
4452
|
"maxLength": 2000
|
|
3941
4453
|
},
|
|
3942
4454
|
"folder": {
|
|
3943
|
-
"description": "
|
|
3944
|
-
"
|
|
3945
|
-
|
|
4455
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
4456
|
+
"anyOf": [
|
|
4457
|
+
{
|
|
4458
|
+
"type": "string",
|
|
4459
|
+
"maxLength": 256,
|
|
4460
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
4461
|
+
},
|
|
4462
|
+
{
|
|
4463
|
+
"type": "null"
|
|
4464
|
+
}
|
|
4465
|
+
]
|
|
3946
4466
|
},
|
|
3947
4467
|
"group": {
|
|
3948
4468
|
"description": "Group label for dashboard organisation (e.g. team or product area).",
|
|
@@ -3966,7 +4486,9 @@
|
|
|
3966
4486
|
"description": "Gate id that was updated."
|
|
3967
4487
|
}
|
|
3968
4488
|
},
|
|
3969
|
-
"required": [
|
|
4489
|
+
"required": [
|
|
4490
|
+
"id"
|
|
4491
|
+
],
|
|
3970
4492
|
"additionalProperties": false,
|
|
3971
4493
|
"description": "Update returns only the id — re-fetch via `GET /api/admin/gates` for the full row."
|
|
3972
4494
|
},
|
|
@@ -3978,7 +4500,9 @@
|
|
|
3978
4500
|
"const": true
|
|
3979
4501
|
}
|
|
3980
4502
|
},
|
|
3981
|
-
"required": [
|
|
4503
|
+
"required": [
|
|
4504
|
+
"ok"
|
|
4505
|
+
],
|
|
3982
4506
|
"additionalProperties": false
|
|
3983
4507
|
},
|
|
3984
4508
|
"EnableGateResponse": {
|
|
@@ -3991,7 +4515,10 @@
|
|
|
3991
4515
|
"type": "boolean"
|
|
3992
4516
|
}
|
|
3993
4517
|
},
|
|
3994
|
-
"required": [
|
|
4518
|
+
"required": [
|
|
4519
|
+
"id",
|
|
4520
|
+
"enabled"
|
|
4521
|
+
],
|
|
3995
4522
|
"additionalProperties": false
|
|
3996
4523
|
},
|
|
3997
4524
|
"DisableGateResponse": {
|
|
@@ -4004,7 +4531,10 @@
|
|
|
4004
4531
|
"type": "boolean"
|
|
4005
4532
|
}
|
|
4006
4533
|
},
|
|
4007
|
-
"required": [
|
|
4534
|
+
"required": [
|
|
4535
|
+
"id",
|
|
4536
|
+
"enabled"
|
|
4537
|
+
],
|
|
4008
4538
|
"additionalProperties": false
|
|
4009
4539
|
},
|
|
4010
4540
|
"ListExperimentsResponse": {
|
|
@@ -4021,8 +4551,9 @@
|
|
|
4021
4551
|
},
|
|
4022
4552
|
"name": {
|
|
4023
4553
|
"type": "string",
|
|
4024
|
-
"
|
|
4025
|
-
"
|
|
4554
|
+
"maxLength": 128,
|
|
4555
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
4556
|
+
"description": "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."
|
|
4026
4557
|
},
|
|
4027
4558
|
"description": {
|
|
4028
4559
|
"anyOf": [
|
|
@@ -4034,6 +4565,16 @@
|
|
|
4034
4565
|
}
|
|
4035
4566
|
]
|
|
4036
4567
|
},
|
|
4568
|
+
"hypothesis": {
|
|
4569
|
+
"anyOf": [
|
|
4570
|
+
{
|
|
4571
|
+
"type": "string"
|
|
4572
|
+
},
|
|
4573
|
+
{
|
|
4574
|
+
"type": "null"
|
|
4575
|
+
}
|
|
4576
|
+
]
|
|
4577
|
+
},
|
|
4037
4578
|
"tag": {
|
|
4038
4579
|
"anyOf": [
|
|
4039
4580
|
{
|
|
@@ -4044,9 +4585,58 @@
|
|
|
4044
4585
|
}
|
|
4045
4586
|
]
|
|
4046
4587
|
},
|
|
4588
|
+
"ownerEmail": {
|
|
4589
|
+
"anyOf": [
|
|
4590
|
+
{
|
|
4591
|
+
"type": "string"
|
|
4592
|
+
},
|
|
4593
|
+
{
|
|
4594
|
+
"type": "null"
|
|
4595
|
+
}
|
|
4596
|
+
]
|
|
4597
|
+
},
|
|
4598
|
+
"audience": {
|
|
4599
|
+
"anyOf": [
|
|
4600
|
+
{
|
|
4601
|
+
"type": "string"
|
|
4602
|
+
},
|
|
4603
|
+
{
|
|
4604
|
+
"type": "null"
|
|
4605
|
+
}
|
|
4606
|
+
]
|
|
4607
|
+
},
|
|
4608
|
+
"bucketBy": {
|
|
4609
|
+
"anyOf": [
|
|
4610
|
+
{
|
|
4611
|
+
"type": "string",
|
|
4612
|
+
"minLength": 1,
|
|
4613
|
+
"maxLength": 128,
|
|
4614
|
+
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$",
|
|
4615
|
+
"description": "User-attribute name used as the bucketing key — e.g. `user_id` (default), `session_id`, `device_id`, or a custom attribute like `company_id` to keep a whole org on one variant. Defaults to `user_id` when omitted."
|
|
4616
|
+
},
|
|
4617
|
+
{
|
|
4618
|
+
"type": "null"
|
|
4619
|
+
}
|
|
4620
|
+
]
|
|
4621
|
+
},
|
|
4622
|
+
"folder": {
|
|
4623
|
+
"anyOf": [
|
|
4624
|
+
{
|
|
4625
|
+
"type": "string"
|
|
4626
|
+
},
|
|
4627
|
+
{
|
|
4628
|
+
"type": "null"
|
|
4629
|
+
}
|
|
4630
|
+
]
|
|
4631
|
+
},
|
|
4047
4632
|
"status": {
|
|
4048
4633
|
"type": "string",
|
|
4049
|
-
"enum": [
|
|
4634
|
+
"enum": [
|
|
4635
|
+
"draft",
|
|
4636
|
+
"running",
|
|
4637
|
+
"stopped",
|
|
4638
|
+
"archived"
|
|
4639
|
+
]
|
|
4050
4640
|
},
|
|
4051
4641
|
"universe": {
|
|
4052
4642
|
"type": "string",
|
|
@@ -4075,7 +4665,11 @@
|
|
|
4075
4665
|
"type": "object",
|
|
4076
4666
|
"additionalProperties": {
|
|
4077
4667
|
"type": "string",
|
|
4078
|
-
"enum": [
|
|
4668
|
+
"enum": [
|
|
4669
|
+
"string",
|
|
4670
|
+
"bool",
|
|
4671
|
+
"number"
|
|
4672
|
+
]
|
|
4079
4673
|
}
|
|
4080
4674
|
},
|
|
4081
4675
|
"groups": {
|
|
@@ -4102,7 +4696,11 @@
|
|
|
4102
4696
|
"additionalProperties": {}
|
|
4103
4697
|
}
|
|
4104
4698
|
},
|
|
4105
|
-
"required": [
|
|
4699
|
+
"required": [
|
|
4700
|
+
"name",
|
|
4701
|
+
"weight",
|
|
4702
|
+
"params"
|
|
4703
|
+
],
|
|
4106
4704
|
"additionalProperties": false,
|
|
4107
4705
|
"description": "One variant in the experiment. Weights across all groups must sum to 10000."
|
|
4108
4706
|
}
|
|
@@ -4152,7 +4750,12 @@
|
|
|
4152
4750
|
"id",
|
|
4153
4751
|
"name",
|
|
4154
4752
|
"description",
|
|
4753
|
+
"hypothesis",
|
|
4155
4754
|
"tag",
|
|
4755
|
+
"ownerEmail",
|
|
4756
|
+
"audience",
|
|
4757
|
+
"bucketBy",
|
|
4758
|
+
"folder",
|
|
4156
4759
|
"status",
|
|
4157
4760
|
"universe",
|
|
4158
4761
|
"targetingGate",
|
|
@@ -4181,7 +4784,10 @@
|
|
|
4181
4784
|
]
|
|
4182
4785
|
}
|
|
4183
4786
|
},
|
|
4184
|
-
"required": [
|
|
4787
|
+
"required": [
|
|
4788
|
+
"data",
|
|
4789
|
+
"next_cursor"
|
|
4790
|
+
],
|
|
4185
4791
|
"additionalProperties": false
|
|
4186
4792
|
},
|
|
4187
4793
|
"GetExperimentResponse": {
|
|
@@ -4193,8 +4799,9 @@
|
|
|
4193
4799
|
},
|
|
4194
4800
|
"name": {
|
|
4195
4801
|
"type": "string",
|
|
4196
|
-
"
|
|
4197
|
-
"
|
|
4802
|
+
"maxLength": 128,
|
|
4803
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
4804
|
+
"description": "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."
|
|
4198
4805
|
},
|
|
4199
4806
|
"description": {
|
|
4200
4807
|
"anyOf": [
|
|
@@ -4206,7 +4813,7 @@
|
|
|
4206
4813
|
}
|
|
4207
4814
|
]
|
|
4208
4815
|
},
|
|
4209
|
-
"
|
|
4816
|
+
"hypothesis": {
|
|
4210
4817
|
"anyOf": [
|
|
4211
4818
|
{
|
|
4212
4819
|
"type": "string"
|
|
@@ -4216,15 +4823,17 @@
|
|
|
4216
4823
|
}
|
|
4217
4824
|
]
|
|
4218
4825
|
},
|
|
4219
|
-
"
|
|
4220
|
-
"
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4826
|
+
"tag": {
|
|
4827
|
+
"anyOf": [
|
|
4828
|
+
{
|
|
4829
|
+
"type": "string"
|
|
4830
|
+
},
|
|
4831
|
+
{
|
|
4832
|
+
"type": "null"
|
|
4833
|
+
}
|
|
4834
|
+
]
|
|
4226
4835
|
},
|
|
4227
|
-
"
|
|
4836
|
+
"ownerEmail": {
|
|
4228
4837
|
"anyOf": [
|
|
4229
4838
|
{
|
|
4230
4839
|
"type": "string"
|
|
@@ -4234,7 +4843,64 @@
|
|
|
4234
4843
|
}
|
|
4235
4844
|
]
|
|
4236
4845
|
},
|
|
4237
|
-
"
|
|
4846
|
+
"audience": {
|
|
4847
|
+
"anyOf": [
|
|
4848
|
+
{
|
|
4849
|
+
"type": "string"
|
|
4850
|
+
},
|
|
4851
|
+
{
|
|
4852
|
+
"type": "null"
|
|
4853
|
+
}
|
|
4854
|
+
]
|
|
4855
|
+
},
|
|
4856
|
+
"bucketBy": {
|
|
4857
|
+
"anyOf": [
|
|
4858
|
+
{
|
|
4859
|
+
"type": "string",
|
|
4860
|
+
"minLength": 1,
|
|
4861
|
+
"maxLength": 128,
|
|
4862
|
+
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$",
|
|
4863
|
+
"description": "User-attribute name used as the bucketing key — e.g. `user_id` (default), `session_id`, `device_id`, or a custom attribute like `company_id` to keep a whole org on one variant. Defaults to `user_id` when omitted."
|
|
4864
|
+
},
|
|
4865
|
+
{
|
|
4866
|
+
"type": "null"
|
|
4867
|
+
}
|
|
4868
|
+
]
|
|
4869
|
+
},
|
|
4870
|
+
"folder": {
|
|
4871
|
+
"anyOf": [
|
|
4872
|
+
{
|
|
4873
|
+
"type": "string"
|
|
4874
|
+
},
|
|
4875
|
+
{
|
|
4876
|
+
"type": "null"
|
|
4877
|
+
}
|
|
4878
|
+
]
|
|
4879
|
+
},
|
|
4880
|
+
"status": {
|
|
4881
|
+
"type": "string",
|
|
4882
|
+
"enum": [
|
|
4883
|
+
"draft",
|
|
4884
|
+
"running",
|
|
4885
|
+
"stopped",
|
|
4886
|
+
"archived"
|
|
4887
|
+
]
|
|
4888
|
+
},
|
|
4889
|
+
"universe": {
|
|
4890
|
+
"type": "string",
|
|
4891
|
+
"description": "Universe name this experiment draws from."
|
|
4892
|
+
},
|
|
4893
|
+
"targetingGate": {
|
|
4894
|
+
"anyOf": [
|
|
4895
|
+
{
|
|
4896
|
+
"type": "string"
|
|
4897
|
+
},
|
|
4898
|
+
{
|
|
4899
|
+
"type": "null"
|
|
4900
|
+
}
|
|
4901
|
+
]
|
|
4902
|
+
},
|
|
4903
|
+
"allocationPct": {
|
|
4238
4904
|
"type": "integer",
|
|
4239
4905
|
"minimum": -9007199254740991,
|
|
4240
4906
|
"maximum": 9007199254740991,
|
|
@@ -4247,7 +4913,11 @@
|
|
|
4247
4913
|
"type": "object",
|
|
4248
4914
|
"additionalProperties": {
|
|
4249
4915
|
"type": "string",
|
|
4250
|
-
"enum": [
|
|
4916
|
+
"enum": [
|
|
4917
|
+
"string",
|
|
4918
|
+
"bool",
|
|
4919
|
+
"number"
|
|
4920
|
+
]
|
|
4251
4921
|
}
|
|
4252
4922
|
},
|
|
4253
4923
|
"groups": {
|
|
@@ -4274,7 +4944,11 @@
|
|
|
4274
4944
|
"additionalProperties": {}
|
|
4275
4945
|
}
|
|
4276
4946
|
},
|
|
4277
|
-
"required": [
|
|
4947
|
+
"required": [
|
|
4948
|
+
"name",
|
|
4949
|
+
"weight",
|
|
4950
|
+
"params"
|
|
4951
|
+
],
|
|
4278
4952
|
"additionalProperties": false,
|
|
4279
4953
|
"description": "One variant in the experiment. Weights across all groups must sum to 10000."
|
|
4280
4954
|
}
|
|
@@ -4324,7 +4998,12 @@
|
|
|
4324
4998
|
"id",
|
|
4325
4999
|
"name",
|
|
4326
5000
|
"description",
|
|
5001
|
+
"hypothesis",
|
|
4327
5002
|
"tag",
|
|
5003
|
+
"ownerEmail",
|
|
5004
|
+
"audience",
|
|
5005
|
+
"bucketBy",
|
|
5006
|
+
"folder",
|
|
4328
5007
|
"status",
|
|
4329
5008
|
"universe",
|
|
4330
5009
|
"targetingGate",
|
|
@@ -4346,8 +5025,9 @@
|
|
|
4346
5025
|
"properties": {
|
|
4347
5026
|
"name": {
|
|
4348
5027
|
"type": "string",
|
|
4349
|
-
"
|
|
4350
|
-
"
|
|
5028
|
+
"maxLength": 128,
|
|
5029
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
5030
|
+
"description": "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."
|
|
4351
5031
|
},
|
|
4352
5032
|
"description": {
|
|
4353
5033
|
"default": null,
|
|
@@ -4362,9 +5042,22 @@
|
|
|
4362
5042
|
}
|
|
4363
5043
|
]
|
|
4364
5044
|
},
|
|
5045
|
+
"hypothesis": {
|
|
5046
|
+
"default": null,
|
|
5047
|
+
"description": "Hypothesis statement shown in the editor. Display-only.",
|
|
5048
|
+
"anyOf": [
|
|
5049
|
+
{
|
|
5050
|
+
"type": "string",
|
|
5051
|
+
"maxLength": 4000
|
|
5052
|
+
},
|
|
5053
|
+
{
|
|
5054
|
+
"type": "null"
|
|
5055
|
+
}
|
|
5056
|
+
]
|
|
5057
|
+
},
|
|
4365
5058
|
"tag": {
|
|
4366
5059
|
"default": null,
|
|
4367
|
-
"description": "
|
|
5060
|
+
"description": "Short tag chip rendered next to the name. Display-only.",
|
|
4368
5061
|
"anyOf": [
|
|
4369
5062
|
{
|
|
4370
5063
|
"type": "string",
|
|
@@ -4375,6 +5068,60 @@
|
|
|
4375
5068
|
}
|
|
4376
5069
|
]
|
|
4377
5070
|
},
|
|
5071
|
+
"owner_email": {
|
|
5072
|
+
"default": null,
|
|
5073
|
+
"description": "Owner email. Display-only.",
|
|
5074
|
+
"anyOf": [
|
|
5075
|
+
{
|
|
5076
|
+
"type": "string",
|
|
5077
|
+
"maxLength": 254
|
|
5078
|
+
},
|
|
5079
|
+
{
|
|
5080
|
+
"type": "null"
|
|
5081
|
+
}
|
|
5082
|
+
]
|
|
5083
|
+
},
|
|
5084
|
+
"audience": {
|
|
5085
|
+
"default": null,
|
|
5086
|
+
"description": "Audience label shown in the editor. Display-only.",
|
|
5087
|
+
"anyOf": [
|
|
5088
|
+
{
|
|
5089
|
+
"type": "string",
|
|
5090
|
+
"maxLength": 256
|
|
5091
|
+
},
|
|
5092
|
+
{
|
|
5093
|
+
"type": "null"
|
|
5094
|
+
}
|
|
5095
|
+
]
|
|
5096
|
+
},
|
|
5097
|
+
"bucket_by": {
|
|
5098
|
+
"default": null,
|
|
5099
|
+
"anyOf": [
|
|
5100
|
+
{
|
|
5101
|
+
"type": "string",
|
|
5102
|
+
"minLength": 1,
|
|
5103
|
+
"maxLength": 128,
|
|
5104
|
+
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$",
|
|
5105
|
+
"description": "User-attribute name used as the bucketing key — e.g. `user_id` (default), `session_id`, `device_id`, or a custom attribute like `company_id` to keep a whole org on one variant. Defaults to `user_id` when omitted."
|
|
5106
|
+
},
|
|
5107
|
+
{
|
|
5108
|
+
"type": "null"
|
|
5109
|
+
}
|
|
5110
|
+
]
|
|
5111
|
+
},
|
|
5112
|
+
"folder": {
|
|
5113
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
5114
|
+
"anyOf": [
|
|
5115
|
+
{
|
|
5116
|
+
"type": "string",
|
|
5117
|
+
"maxLength": 256,
|
|
5118
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
5119
|
+
},
|
|
5120
|
+
{
|
|
5121
|
+
"type": "null"
|
|
5122
|
+
}
|
|
5123
|
+
]
|
|
5124
|
+
},
|
|
4378
5125
|
"universe": {
|
|
4379
5126
|
"type": "string",
|
|
4380
5127
|
"minLength": 1,
|
|
@@ -4410,7 +5157,11 @@
|
|
|
4410
5157
|
"type": "object",
|
|
4411
5158
|
"additionalProperties": {
|
|
4412
5159
|
"type": "string",
|
|
4413
|
-
"enum": [
|
|
5160
|
+
"enum": [
|
|
5161
|
+
"string",
|
|
5162
|
+
"bool",
|
|
5163
|
+
"number"
|
|
5164
|
+
]
|
|
4414
5165
|
},
|
|
4415
5166
|
"description": "Map of param-name → scalar type. Defines the shape of `groups[].params`. Example: `{ headline: 'string', show_cta: 'bool' }`."
|
|
4416
5167
|
},
|
|
@@ -4439,7 +5190,11 @@
|
|
|
4439
5190
|
"additionalProperties": {}
|
|
4440
5191
|
}
|
|
4441
5192
|
},
|
|
4442
|
-
"required": [
|
|
5193
|
+
"required": [
|
|
5194
|
+
"name",
|
|
5195
|
+
"weight",
|
|
5196
|
+
"params"
|
|
5197
|
+
],
|
|
4443
5198
|
"additionalProperties": false,
|
|
4444
5199
|
"description": "One variant in the experiment. Weights across all groups must sum to 10000."
|
|
4445
5200
|
},
|
|
@@ -4470,12 +5225,63 @@
|
|
|
4470
5225
|
"default": false,
|
|
4471
5226
|
"description": "Enable sequential testing (always-valid p-values). Requires Premium plan or higher.",
|
|
4472
5227
|
"type": "boolean"
|
|
5228
|
+
},
|
|
5229
|
+
"goal_metric": {
|
|
5230
|
+
"description": "Single goal metric defined inline as a DSL query. The underlying event is auto-created if missing.",
|
|
5231
|
+
"type": "object",
|
|
5232
|
+
"properties": {
|
|
5233
|
+
"name": {
|
|
5234
|
+
"type": "string",
|
|
5235
|
+
"maxLength": 128,
|
|
5236
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$"
|
|
5237
|
+
},
|
|
5238
|
+
"query": {
|
|
5239
|
+
"type": "string",
|
|
5240
|
+
"minLength": 1,
|
|
5241
|
+
"maxLength": 4096,
|
|
5242
|
+
"description": "Metric DSL string, e.g. `count_users(checkout_completed)`."
|
|
5243
|
+
}
|
|
5244
|
+
},
|
|
5245
|
+
"required": [
|
|
5246
|
+
"query"
|
|
5247
|
+
],
|
|
5248
|
+
"additionalProperties": false
|
|
5249
|
+
},
|
|
5250
|
+
"guardrail_metrics": {
|
|
5251
|
+
"default": [],
|
|
5252
|
+
"description": "Up to 10 guardrail metrics defined inline. Each is upserted (event + metric) and attached with role=guardrail.",
|
|
5253
|
+
"maxItems": 10,
|
|
5254
|
+
"type": "array",
|
|
5255
|
+
"items": {
|
|
5256
|
+
"type": "object",
|
|
5257
|
+
"properties": {
|
|
5258
|
+
"name": {
|
|
5259
|
+
"type": "string",
|
|
5260
|
+
"maxLength": 128,
|
|
5261
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$"
|
|
5262
|
+
},
|
|
5263
|
+
"query": {
|
|
5264
|
+
"type": "string",
|
|
5265
|
+
"minLength": 1,
|
|
5266
|
+
"maxLength": 4096,
|
|
5267
|
+
"description": "Metric DSL string, e.g. `count_users(checkout_completed)`."
|
|
5268
|
+
}
|
|
5269
|
+
},
|
|
5270
|
+
"required": [
|
|
5271
|
+
"query"
|
|
5272
|
+
],
|
|
5273
|
+
"additionalProperties": false
|
|
5274
|
+
}
|
|
4473
5275
|
}
|
|
4474
5276
|
},
|
|
4475
5277
|
"required": [
|
|
4476
5278
|
"name",
|
|
4477
5279
|
"description",
|
|
5280
|
+
"hypothesis",
|
|
4478
5281
|
"tag",
|
|
5282
|
+
"owner_email",
|
|
5283
|
+
"audience",
|
|
5284
|
+
"bucket_by",
|
|
4479
5285
|
"universe",
|
|
4480
5286
|
"targeting_gate",
|
|
4481
5287
|
"allocation_pct",
|
|
@@ -4484,7 +5290,8 @@
|
|
|
4484
5290
|
"significance_threshold",
|
|
4485
5291
|
"min_runtime_days",
|
|
4486
5292
|
"min_sample_size",
|
|
4487
|
-
"sequential_testing"
|
|
5293
|
+
"sequential_testing",
|
|
5294
|
+
"guardrail_metrics"
|
|
4488
5295
|
],
|
|
4489
5296
|
"additionalProperties": false,
|
|
4490
5297
|
"description": "Body for `POST /api/admin/experiments`. `name`, `universe`, and `groups` (≥2, weights sum to 10000) required."
|
|
@@ -4498,11 +5305,15 @@
|
|
|
4498
5305
|
},
|
|
4499
5306
|
"name": {
|
|
4500
5307
|
"type": "string",
|
|
4501
|
-
"
|
|
4502
|
-
"
|
|
5308
|
+
"maxLength": 128,
|
|
5309
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
5310
|
+
"description": "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."
|
|
4503
5311
|
}
|
|
4504
5312
|
},
|
|
4505
|
-
"required": [
|
|
5313
|
+
"required": [
|
|
5314
|
+
"id",
|
|
5315
|
+
"name"
|
|
5316
|
+
],
|
|
4506
5317
|
"additionalProperties": false
|
|
4507
5318
|
},
|
|
4508
5319
|
"UpdateExperimentRequest": {
|
|
@@ -4510,8 +5321,9 @@
|
|
|
4510
5321
|
"properties": {
|
|
4511
5322
|
"name": {
|
|
4512
5323
|
"type": "string",
|
|
4513
|
-
"
|
|
4514
|
-
"
|
|
5324
|
+
"maxLength": 128,
|
|
5325
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
5326
|
+
"description": "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."
|
|
4515
5327
|
},
|
|
4516
5328
|
"description": {
|
|
4517
5329
|
"anyOf": [
|
|
@@ -4524,6 +5336,17 @@
|
|
|
4524
5336
|
}
|
|
4525
5337
|
]
|
|
4526
5338
|
},
|
|
5339
|
+
"hypothesis": {
|
|
5340
|
+
"anyOf": [
|
|
5341
|
+
{
|
|
5342
|
+
"type": "string",
|
|
5343
|
+
"maxLength": 4000
|
|
5344
|
+
},
|
|
5345
|
+
{
|
|
5346
|
+
"type": "null"
|
|
5347
|
+
}
|
|
5348
|
+
]
|
|
5349
|
+
},
|
|
4527
5350
|
"tag": {
|
|
4528
5351
|
"anyOf": [
|
|
4529
5352
|
{
|
|
@@ -4535,6 +5358,55 @@
|
|
|
4535
5358
|
}
|
|
4536
5359
|
]
|
|
4537
5360
|
},
|
|
5361
|
+
"owner_email": {
|
|
5362
|
+
"anyOf": [
|
|
5363
|
+
{
|
|
5364
|
+
"type": "string",
|
|
5365
|
+
"maxLength": 254
|
|
5366
|
+
},
|
|
5367
|
+
{
|
|
5368
|
+
"type": "null"
|
|
5369
|
+
}
|
|
5370
|
+
]
|
|
5371
|
+
},
|
|
5372
|
+
"audience": {
|
|
5373
|
+
"anyOf": [
|
|
5374
|
+
{
|
|
5375
|
+
"type": "string",
|
|
5376
|
+
"maxLength": 256
|
|
5377
|
+
},
|
|
5378
|
+
{
|
|
5379
|
+
"type": "null"
|
|
5380
|
+
}
|
|
5381
|
+
]
|
|
5382
|
+
},
|
|
5383
|
+
"bucket_by": {
|
|
5384
|
+
"anyOf": [
|
|
5385
|
+
{
|
|
5386
|
+
"type": "string",
|
|
5387
|
+
"minLength": 1,
|
|
5388
|
+
"maxLength": 128,
|
|
5389
|
+
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$",
|
|
5390
|
+
"description": "User-attribute name used as the bucketing key — e.g. `user_id` (default), `session_id`, `device_id`, or a custom attribute like `company_id` to keep a whole org on one variant. Defaults to `user_id` when omitted."
|
|
5391
|
+
},
|
|
5392
|
+
{
|
|
5393
|
+
"type": "null"
|
|
5394
|
+
}
|
|
5395
|
+
]
|
|
5396
|
+
},
|
|
5397
|
+
"folder": {
|
|
5398
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
5399
|
+
"anyOf": [
|
|
5400
|
+
{
|
|
5401
|
+
"type": "string",
|
|
5402
|
+
"maxLength": 256,
|
|
5403
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
5404
|
+
},
|
|
5405
|
+
{
|
|
5406
|
+
"type": "null"
|
|
5407
|
+
}
|
|
5408
|
+
]
|
|
5409
|
+
},
|
|
4538
5410
|
"targeting_gate": {
|
|
4539
5411
|
"anyOf": [
|
|
4540
5412
|
{
|
|
@@ -4565,7 +5437,11 @@
|
|
|
4565
5437
|
"type": "object",
|
|
4566
5438
|
"additionalProperties": {
|
|
4567
5439
|
"type": "string",
|
|
4568
|
-
"enum": [
|
|
5440
|
+
"enum": [
|
|
5441
|
+
"string",
|
|
5442
|
+
"bool",
|
|
5443
|
+
"number"
|
|
5444
|
+
]
|
|
4569
5445
|
},
|
|
4570
5446
|
"description": "Map of param-name → scalar type. Defines the shape of `groups[].params`. Example: `{ headline: 'string', show_cta: 'bool' }`."
|
|
4571
5447
|
},
|
|
@@ -4595,7 +5471,11 @@
|
|
|
4595
5471
|
"additionalProperties": {}
|
|
4596
5472
|
}
|
|
4597
5473
|
},
|
|
4598
|
-
"required": [
|
|
5474
|
+
"required": [
|
|
5475
|
+
"name",
|
|
5476
|
+
"weight",
|
|
5477
|
+
"params"
|
|
5478
|
+
],
|
|
4599
5479
|
"additionalProperties": false,
|
|
4600
5480
|
"description": "One variant in the experiment. Weights across all groups must sum to 10000."
|
|
4601
5481
|
}
|
|
@@ -4617,6 +5497,52 @@
|
|
|
4617
5497
|
},
|
|
4618
5498
|
"sequential_testing": {
|
|
4619
5499
|
"type": "boolean"
|
|
5500
|
+
},
|
|
5501
|
+
"goal_metric": {
|
|
5502
|
+
"description": "Replaces the goal metric (event auto-upserted).",
|
|
5503
|
+
"type": "object",
|
|
5504
|
+
"properties": {
|
|
5505
|
+
"name": {
|
|
5506
|
+
"type": "string",
|
|
5507
|
+
"maxLength": 128,
|
|
5508
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$"
|
|
5509
|
+
},
|
|
5510
|
+
"query": {
|
|
5511
|
+
"type": "string",
|
|
5512
|
+
"minLength": 1,
|
|
5513
|
+
"maxLength": 4096,
|
|
5514
|
+
"description": "Metric DSL string, e.g. `count_users(checkout_completed)`."
|
|
5515
|
+
}
|
|
5516
|
+
},
|
|
5517
|
+
"required": [
|
|
5518
|
+
"query"
|
|
5519
|
+
],
|
|
5520
|
+
"additionalProperties": false
|
|
5521
|
+
},
|
|
5522
|
+
"guardrail_metrics": {
|
|
5523
|
+
"description": "Replaces the guardrail set wholesale (event auto-upserted per entry).",
|
|
5524
|
+
"maxItems": 10,
|
|
5525
|
+
"type": "array",
|
|
5526
|
+
"items": {
|
|
5527
|
+
"type": "object",
|
|
5528
|
+
"properties": {
|
|
5529
|
+
"name": {
|
|
5530
|
+
"type": "string",
|
|
5531
|
+
"maxLength": 128,
|
|
5532
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$"
|
|
5533
|
+
},
|
|
5534
|
+
"query": {
|
|
5535
|
+
"type": "string",
|
|
5536
|
+
"minLength": 1,
|
|
5537
|
+
"maxLength": 4096,
|
|
5538
|
+
"description": "Metric DSL string, e.g. `count_users(checkout_completed)`."
|
|
5539
|
+
}
|
|
5540
|
+
},
|
|
5541
|
+
"required": [
|
|
5542
|
+
"query"
|
|
5543
|
+
],
|
|
5544
|
+
"additionalProperties": false
|
|
5545
|
+
}
|
|
4620
5546
|
}
|
|
4621
5547
|
},
|
|
4622
5548
|
"additionalProperties": false,
|
|
@@ -4630,7 +5556,9 @@
|
|
|
4630
5556
|
"description": "Experiment id that was updated."
|
|
4631
5557
|
}
|
|
4632
5558
|
},
|
|
4633
|
-
"required": [
|
|
5559
|
+
"required": [
|
|
5560
|
+
"id"
|
|
5561
|
+
],
|
|
4634
5562
|
"additionalProperties": false
|
|
4635
5563
|
},
|
|
4636
5564
|
"DeleteExperimentResponse": {
|
|
@@ -4641,7 +5569,9 @@
|
|
|
4641
5569
|
"const": true
|
|
4642
5570
|
}
|
|
4643
5571
|
},
|
|
4644
|
-
"required": [
|
|
5572
|
+
"required": [
|
|
5573
|
+
"ok"
|
|
5574
|
+
],
|
|
4645
5575
|
"additionalProperties": false
|
|
4646
5576
|
},
|
|
4647
5577
|
"SetExperimentStatusRequest": {
|
|
@@ -4649,11 +5579,18 @@
|
|
|
4649
5579
|
"properties": {
|
|
4650
5580
|
"status": {
|
|
4651
5581
|
"type": "string",
|
|
4652
|
-
"enum": [
|
|
4653
|
-
|
|
5582
|
+
"enum": [
|
|
5583
|
+
"draft",
|
|
5584
|
+
"running",
|
|
5585
|
+
"stopped",
|
|
5586
|
+
"archived"
|
|
5587
|
+
],
|
|
5588
|
+
"description": "Target status. Allowed transitions: `draft → running`, `running → stopped`, `stopped → archived`, `draft → archived`, and `archived → draft` (restore — only if the experiment never started). Restarting an archived experiment directly is not allowed; restore it to draft first, then start."
|
|
4654
5589
|
}
|
|
4655
5590
|
},
|
|
4656
|
-
"required": [
|
|
5591
|
+
"required": [
|
|
5592
|
+
"status"
|
|
5593
|
+
],
|
|
4657
5594
|
"additionalProperties": false,
|
|
4658
5595
|
"description": "Body for `POST /api/admin/experiments/{id}/status`."
|
|
4659
5596
|
},
|
|
@@ -4665,10 +5602,18 @@
|
|
|
4665
5602
|
},
|
|
4666
5603
|
"status": {
|
|
4667
5604
|
"type": "string",
|
|
4668
|
-
"enum": [
|
|
5605
|
+
"enum": [
|
|
5606
|
+
"draft",
|
|
5607
|
+
"running",
|
|
5608
|
+
"stopped",
|
|
5609
|
+
"archived"
|
|
5610
|
+
]
|
|
4669
5611
|
}
|
|
4670
5612
|
},
|
|
4671
|
-
"required": [
|
|
5613
|
+
"required": [
|
|
5614
|
+
"id",
|
|
5615
|
+
"status"
|
|
5616
|
+
],
|
|
4672
5617
|
"additionalProperties": false
|
|
4673
5618
|
},
|
|
4674
5619
|
"SetExperimentMetricsRequest": {
|
|
@@ -4685,17 +5630,26 @@
|
|
|
4685
5630
|
},
|
|
4686
5631
|
"role": {
|
|
4687
5632
|
"type": "string",
|
|
4688
|
-
"enum": [
|
|
5633
|
+
"enum": [
|
|
5634
|
+
"goal",
|
|
5635
|
+
"guardrail",
|
|
5636
|
+
"secondary"
|
|
5637
|
+
],
|
|
4689
5638
|
"description": "Metric role. `goal` drives the decision, `guardrail` blocks ship if degraded, `secondary` is informational."
|
|
4690
5639
|
}
|
|
4691
5640
|
},
|
|
4692
|
-
"required": [
|
|
5641
|
+
"required": [
|
|
5642
|
+
"metric_id",
|
|
5643
|
+
"role"
|
|
5644
|
+
],
|
|
4693
5645
|
"additionalProperties": false
|
|
4694
5646
|
},
|
|
4695
5647
|
"description": "Replacement metrics list — replaces the current attachments wholesale."
|
|
4696
5648
|
}
|
|
4697
5649
|
},
|
|
4698
|
-
"required": [
|
|
5650
|
+
"required": [
|
|
5651
|
+
"metrics"
|
|
5652
|
+
],
|
|
4699
5653
|
"additionalProperties": false,
|
|
4700
5654
|
"description": "Body for `POST /api/admin/experiments/{id}/metrics`. Replaces the experiment's metric attachments wholesale. Returns `422` if any `metric_id` is unknown."
|
|
4701
5655
|
},
|
|
@@ -4715,15 +5669,25 @@
|
|
|
4715
5669
|
},
|
|
4716
5670
|
"role": {
|
|
4717
5671
|
"type": "string",
|
|
4718
|
-
"enum": [
|
|
5672
|
+
"enum": [
|
|
5673
|
+
"goal",
|
|
5674
|
+
"guardrail",
|
|
5675
|
+
"secondary"
|
|
5676
|
+
]
|
|
4719
5677
|
}
|
|
4720
5678
|
},
|
|
4721
|
-
"required": [
|
|
5679
|
+
"required": [
|
|
5680
|
+
"metric_id",
|
|
5681
|
+
"role"
|
|
5682
|
+
],
|
|
4722
5683
|
"additionalProperties": false
|
|
4723
5684
|
}
|
|
4724
5685
|
}
|
|
4725
5686
|
},
|
|
4726
|
-
"required": [
|
|
5687
|
+
"required": [
|
|
5688
|
+
"id",
|
|
5689
|
+
"metrics"
|
|
5690
|
+
],
|
|
4727
5691
|
"additionalProperties": false
|
|
4728
5692
|
},
|
|
4729
5693
|
"GetExperimentResultsResponse": {
|
|
@@ -4737,15 +5701,25 @@
|
|
|
4737
5701
|
},
|
|
4738
5702
|
"name": {
|
|
4739
5703
|
"type": "string",
|
|
4740
|
-
"
|
|
4741
|
-
"
|
|
5704
|
+
"maxLength": 128,
|
|
5705
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
5706
|
+
"description": "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."
|
|
4742
5707
|
},
|
|
4743
5708
|
"status": {
|
|
4744
5709
|
"type": "string",
|
|
4745
|
-
"enum": [
|
|
5710
|
+
"enum": [
|
|
5711
|
+
"draft",
|
|
5712
|
+
"running",
|
|
5713
|
+
"stopped",
|
|
5714
|
+
"archived"
|
|
5715
|
+
]
|
|
4746
5716
|
}
|
|
4747
5717
|
},
|
|
4748
|
-
"required": [
|
|
5718
|
+
"required": [
|
|
5719
|
+
"id",
|
|
5720
|
+
"name",
|
|
5721
|
+
"status"
|
|
5722
|
+
],
|
|
4749
5723
|
"additionalProperties": false
|
|
4750
5724
|
},
|
|
4751
5725
|
"results": {
|
|
@@ -4829,7 +5803,10 @@
|
|
|
4829
5803
|
}
|
|
4830
5804
|
}
|
|
4831
5805
|
},
|
|
4832
|
-
"required": [
|
|
5806
|
+
"required": [
|
|
5807
|
+
"experiment",
|
|
5808
|
+
"results"
|
|
5809
|
+
],
|
|
4833
5810
|
"additionalProperties": false
|
|
4834
5811
|
},
|
|
4835
5812
|
"GetExperimentTimeseriesResponse": {
|
|
@@ -4843,15 +5820,25 @@
|
|
|
4843
5820
|
},
|
|
4844
5821
|
"name": {
|
|
4845
5822
|
"type": "string",
|
|
4846
|
-
"
|
|
4847
|
-
"
|
|
5823
|
+
"maxLength": 128,
|
|
5824
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
5825
|
+
"description": "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."
|
|
4848
5826
|
},
|
|
4849
5827
|
"status": {
|
|
4850
5828
|
"type": "string",
|
|
4851
|
-
"enum": [
|
|
5829
|
+
"enum": [
|
|
5830
|
+
"draft",
|
|
5831
|
+
"running",
|
|
5832
|
+
"stopped",
|
|
5833
|
+
"archived"
|
|
5834
|
+
]
|
|
4852
5835
|
}
|
|
4853
5836
|
},
|
|
4854
|
-
"required": [
|
|
5837
|
+
"required": [
|
|
5838
|
+
"id",
|
|
5839
|
+
"name",
|
|
5840
|
+
"status"
|
|
5841
|
+
],
|
|
4855
5842
|
"additionalProperties": false
|
|
4856
5843
|
},
|
|
4857
5844
|
"series": {
|
|
@@ -4935,7 +5922,10 @@
|
|
|
4935
5922
|
}
|
|
4936
5923
|
}
|
|
4937
5924
|
},
|
|
4938
|
-
"required": [
|
|
5925
|
+
"required": [
|
|
5926
|
+
"experiment",
|
|
5927
|
+
"series"
|
|
5928
|
+
],
|
|
4939
5929
|
"additionalProperties": false
|
|
4940
5930
|
},
|
|
4941
5931
|
"ReanalyzeExperimentResponse": {
|
|
@@ -4949,7 +5939,10 @@
|
|
|
4949
5939
|
"const": true
|
|
4950
5940
|
}
|
|
4951
5941
|
},
|
|
4952
|
-
"required": [
|
|
5942
|
+
"required": [
|
|
5943
|
+
"id",
|
|
5944
|
+
"queued"
|
|
5945
|
+
],
|
|
4953
5946
|
"additionalProperties": false
|
|
4954
5947
|
},
|
|
4955
5948
|
"ListConfigsResponse": {
|
|
@@ -5008,10 +6001,18 @@
|
|
|
5008
6001
|
"description": "Email/id of the actor who published this version."
|
|
5009
6002
|
}
|
|
5010
6003
|
},
|
|
5011
|
-
"required": [
|
|
6004
|
+
"required": [
|
|
6005
|
+
"version",
|
|
6006
|
+
"publishedAt",
|
|
6007
|
+
"publishedBy"
|
|
6008
|
+
],
|
|
5012
6009
|
"additionalProperties": false
|
|
5013
6010
|
},
|
|
5014
|
-
"required": [
|
|
6011
|
+
"required": [
|
|
6012
|
+
"dev",
|
|
6013
|
+
"staging",
|
|
6014
|
+
"prod"
|
|
6015
|
+
],
|
|
5015
6016
|
"description": "Per-env latest published version metadata."
|
|
5016
6017
|
},
|
|
5017
6018
|
"drafts": {
|
|
@@ -5034,26 +6035,50 @@
|
|
|
5034
6035
|
"description": "Published version the draft was forked from."
|
|
5035
6036
|
}
|
|
5036
6037
|
},
|
|
5037
|
-
"required": [
|
|
6038
|
+
"required": [
|
|
6039
|
+
"updatedAt",
|
|
6040
|
+
"authorEmail",
|
|
6041
|
+
"baseVersion"
|
|
6042
|
+
],
|
|
5038
6043
|
"additionalProperties": false
|
|
5039
6044
|
},
|
|
5040
|
-
"required": [
|
|
6045
|
+
"required": [
|
|
6046
|
+
"dev",
|
|
6047
|
+
"staging",
|
|
6048
|
+
"prod"
|
|
6049
|
+
],
|
|
5041
6050
|
"description": "Per-env active drafts (if any)."
|
|
5042
6051
|
},
|
|
5043
6052
|
"values": {
|
|
5044
6053
|
"description": "Per-env latest published values (only returned by `GET /{id}`, not list).",
|
|
5045
6054
|
"type": "object",
|
|
5046
6055
|
"additionalProperties": {},
|
|
5047
|
-
"required": [
|
|
6056
|
+
"required": [
|
|
6057
|
+
"dev",
|
|
6058
|
+
"staging",
|
|
6059
|
+
"prod"
|
|
6060
|
+
]
|
|
5048
6061
|
},
|
|
5049
6062
|
"draftValues": {
|
|
5050
6063
|
"description": "Per-env draft values (only returned by `GET /{id}`).",
|
|
5051
6064
|
"type": "object",
|
|
5052
6065
|
"additionalProperties": {},
|
|
5053
|
-
"required": [
|
|
6066
|
+
"required": [
|
|
6067
|
+
"dev",
|
|
6068
|
+
"staging",
|
|
6069
|
+
"prod"
|
|
6070
|
+
]
|
|
5054
6071
|
}
|
|
5055
6072
|
},
|
|
5056
|
-
"required": [
|
|
6073
|
+
"required": [
|
|
6074
|
+
"id",
|
|
6075
|
+
"name",
|
|
6076
|
+
"description",
|
|
6077
|
+
"schema",
|
|
6078
|
+
"updatedAt",
|
|
6079
|
+
"envs",
|
|
6080
|
+
"drafts"
|
|
6081
|
+
],
|
|
5057
6082
|
"additionalProperties": false
|
|
5058
6083
|
}
|
|
5059
6084
|
},
|
|
@@ -5068,7 +6093,10 @@
|
|
|
5068
6093
|
]
|
|
5069
6094
|
}
|
|
5070
6095
|
},
|
|
5071
|
-
"required": [
|
|
6096
|
+
"required": [
|
|
6097
|
+
"data",
|
|
6098
|
+
"next_cursor"
|
|
6099
|
+
],
|
|
5072
6100
|
"additionalProperties": false
|
|
5073
6101
|
},
|
|
5074
6102
|
"GetConfigResponse": {
|
|
@@ -5122,10 +6150,18 @@
|
|
|
5122
6150
|
"description": "Email/id of the actor who published this version."
|
|
5123
6151
|
}
|
|
5124
6152
|
},
|
|
5125
|
-
"required": [
|
|
6153
|
+
"required": [
|
|
6154
|
+
"version",
|
|
6155
|
+
"publishedAt",
|
|
6156
|
+
"publishedBy"
|
|
6157
|
+
],
|
|
5126
6158
|
"additionalProperties": false
|
|
5127
6159
|
},
|
|
5128
|
-
"required": [
|
|
6160
|
+
"required": [
|
|
6161
|
+
"dev",
|
|
6162
|
+
"staging",
|
|
6163
|
+
"prod"
|
|
6164
|
+
],
|
|
5129
6165
|
"description": "Per-env latest published version metadata."
|
|
5130
6166
|
},
|
|
5131
6167
|
"drafts": {
|
|
@@ -5148,26 +6184,50 @@
|
|
|
5148
6184
|
"description": "Published version the draft was forked from."
|
|
5149
6185
|
}
|
|
5150
6186
|
},
|
|
5151
|
-
"required": [
|
|
6187
|
+
"required": [
|
|
6188
|
+
"updatedAt",
|
|
6189
|
+
"authorEmail",
|
|
6190
|
+
"baseVersion"
|
|
6191
|
+
],
|
|
5152
6192
|
"additionalProperties": false
|
|
5153
6193
|
},
|
|
5154
|
-
"required": [
|
|
6194
|
+
"required": [
|
|
6195
|
+
"dev",
|
|
6196
|
+
"staging",
|
|
6197
|
+
"prod"
|
|
6198
|
+
],
|
|
5155
6199
|
"description": "Per-env active drafts (if any)."
|
|
5156
6200
|
},
|
|
5157
6201
|
"values": {
|
|
5158
6202
|
"description": "Per-env latest published values (only returned by `GET /{id}`, not list).",
|
|
5159
6203
|
"type": "object",
|
|
5160
6204
|
"additionalProperties": {},
|
|
5161
|
-
"required": [
|
|
6205
|
+
"required": [
|
|
6206
|
+
"dev",
|
|
6207
|
+
"staging",
|
|
6208
|
+
"prod"
|
|
6209
|
+
]
|
|
5162
6210
|
},
|
|
5163
6211
|
"draftValues": {
|
|
5164
6212
|
"description": "Per-env draft values (only returned by `GET /{id}`).",
|
|
5165
6213
|
"type": "object",
|
|
5166
6214
|
"additionalProperties": {},
|
|
5167
|
-
"required": [
|
|
6215
|
+
"required": [
|
|
6216
|
+
"dev",
|
|
6217
|
+
"staging",
|
|
6218
|
+
"prod"
|
|
6219
|
+
]
|
|
5168
6220
|
}
|
|
5169
6221
|
},
|
|
5170
|
-
"required": [
|
|
6222
|
+
"required": [
|
|
6223
|
+
"id",
|
|
6224
|
+
"name",
|
|
6225
|
+
"description",
|
|
6226
|
+
"schema",
|
|
6227
|
+
"updatedAt",
|
|
6228
|
+
"envs",
|
|
6229
|
+
"drafts"
|
|
6230
|
+
],
|
|
5171
6231
|
"additionalProperties": false
|
|
5172
6232
|
},
|
|
5173
6233
|
"CreateConfigRequest": {
|
|
@@ -5183,6 +6243,19 @@
|
|
|
5183
6243
|
"type": "string",
|
|
5184
6244
|
"maxLength": 512
|
|
5185
6245
|
},
|
|
6246
|
+
"folder": {
|
|
6247
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
6248
|
+
"anyOf": [
|
|
6249
|
+
{
|
|
6250
|
+
"type": "string",
|
|
6251
|
+
"maxLength": 256,
|
|
6252
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
6253
|
+
},
|
|
6254
|
+
{
|
|
6255
|
+
"type": "null"
|
|
6256
|
+
}
|
|
6257
|
+
]
|
|
6258
|
+
},
|
|
5186
6259
|
"schema": {
|
|
5187
6260
|
"type": "object",
|
|
5188
6261
|
"additionalProperties": {},
|
|
@@ -5194,13 +6267,20 @@
|
|
|
5194
6267
|
{
|
|
5195
6268
|
"type": "object",
|
|
5196
6269
|
"additionalProperties": {},
|
|
5197
|
-
"required": [
|
|
6270
|
+
"required": [
|
|
6271
|
+
"dev",
|
|
6272
|
+
"staging",
|
|
6273
|
+
"prod"
|
|
6274
|
+
]
|
|
5198
6275
|
}
|
|
5199
6276
|
],
|
|
5200
6277
|
"description": "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."
|
|
5201
6278
|
}
|
|
5202
6279
|
},
|
|
5203
|
-
"required": [
|
|
6280
|
+
"required": [
|
|
6281
|
+
"name",
|
|
6282
|
+
"schema"
|
|
6283
|
+
],
|
|
5204
6284
|
"additionalProperties": false,
|
|
5205
6285
|
"description": "Body for `POST /api/admin/configs`. `name` + `schema` required."
|
|
5206
6286
|
},
|
|
@@ -5217,7 +6297,10 @@
|
|
|
5217
6297
|
"description": "Stable config key in `folder.name` form (two lowercase segments separated by a dot, e.g. `pricing.tiers`). Used by SDKs as `Shipeasy.getConfig('<name>')`. Immutable after create."
|
|
5218
6298
|
}
|
|
5219
6299
|
},
|
|
5220
|
-
"required": [
|
|
6300
|
+
"required": [
|
|
6301
|
+
"id",
|
|
6302
|
+
"name"
|
|
6303
|
+
],
|
|
5221
6304
|
"additionalProperties": false
|
|
5222
6305
|
},
|
|
5223
6306
|
"UpdateConfigRequest": {
|
|
@@ -5230,6 +6313,19 @@
|
|
|
5230
6313
|
},
|
|
5231
6314
|
"value": {
|
|
5232
6315
|
"description": "Flat value applied to **every** env. Publishes a new version per env. To target one env, use `PUT /{id}/drafts` then `POST /{id}/publish`."
|
|
6316
|
+
},
|
|
6317
|
+
"folder": {
|
|
6318
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
6319
|
+
"anyOf": [
|
|
6320
|
+
{
|
|
6321
|
+
"type": "string",
|
|
6322
|
+
"maxLength": 256,
|
|
6323
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
6324
|
+
},
|
|
6325
|
+
{
|
|
6326
|
+
"type": "null"
|
|
6327
|
+
}
|
|
6328
|
+
]
|
|
5233
6329
|
}
|
|
5234
6330
|
},
|
|
5235
6331
|
"additionalProperties": false,
|
|
@@ -5243,7 +6339,9 @@
|
|
|
5243
6339
|
"description": "Config id that was updated."
|
|
5244
6340
|
}
|
|
5245
6341
|
},
|
|
5246
|
-
"required": [
|
|
6342
|
+
"required": [
|
|
6343
|
+
"id"
|
|
6344
|
+
],
|
|
5247
6345
|
"additionalProperties": false
|
|
5248
6346
|
},
|
|
5249
6347
|
"DeleteConfigResponse": {
|
|
@@ -5254,7 +6352,9 @@
|
|
|
5254
6352
|
"const": true
|
|
5255
6353
|
}
|
|
5256
6354
|
},
|
|
5257
|
-
"required": [
|
|
6355
|
+
"required": [
|
|
6356
|
+
"ok"
|
|
6357
|
+
],
|
|
5258
6358
|
"additionalProperties": false
|
|
5259
6359
|
},
|
|
5260
6360
|
"SaveConfigDraftRequest": {
|
|
@@ -5262,14 +6362,21 @@
|
|
|
5262
6362
|
"properties": {
|
|
5263
6363
|
"env": {
|
|
5264
6364
|
"type": "string",
|
|
5265
|
-
"enum": [
|
|
6365
|
+
"enum": [
|
|
6366
|
+
"dev",
|
|
6367
|
+
"staging",
|
|
6368
|
+
"prod"
|
|
6369
|
+
],
|
|
5266
6370
|
"description": "Target environment. One of the project's configured envs (`dev`, `stage`, `prod`)."
|
|
5267
6371
|
},
|
|
5268
6372
|
"value": {
|
|
5269
6373
|
"description": "Draft value to stage on `env`. Validated against the config's current schema."
|
|
5270
6374
|
}
|
|
5271
6375
|
},
|
|
5272
|
-
"required": [
|
|
6376
|
+
"required": [
|
|
6377
|
+
"env",
|
|
6378
|
+
"value"
|
|
6379
|
+
],
|
|
5273
6380
|
"additionalProperties": false,
|
|
5274
6381
|
"description": "Body for `PUT /api/admin/configs/{id}/drafts`. Stages a value for a single env without publishing."
|
|
5275
6382
|
},
|
|
@@ -5281,7 +6388,11 @@
|
|
|
5281
6388
|
},
|
|
5282
6389
|
"env": {
|
|
5283
6390
|
"type": "string",
|
|
5284
|
-
"enum": [
|
|
6391
|
+
"enum": [
|
|
6392
|
+
"dev",
|
|
6393
|
+
"staging",
|
|
6394
|
+
"prod"
|
|
6395
|
+
],
|
|
5285
6396
|
"description": "Target environment. One of the project's configured envs (`dev`, `stage`, `prod`)."
|
|
5286
6397
|
},
|
|
5287
6398
|
"baseVersion": {
|
|
@@ -5294,7 +6405,12 @@
|
|
|
5294
6405
|
"type": "string"
|
|
5295
6406
|
}
|
|
5296
6407
|
},
|
|
5297
|
-
"required": [
|
|
6408
|
+
"required": [
|
|
6409
|
+
"id",
|
|
6410
|
+
"env",
|
|
6411
|
+
"baseVersion",
|
|
6412
|
+
"updatedAt"
|
|
6413
|
+
],
|
|
5298
6414
|
"additionalProperties": false
|
|
5299
6415
|
},
|
|
5300
6416
|
"DiscardConfigDraftRequest": {
|
|
@@ -5302,11 +6418,17 @@
|
|
|
5302
6418
|
"properties": {
|
|
5303
6419
|
"env": {
|
|
5304
6420
|
"type": "string",
|
|
5305
|
-
"enum": [
|
|
6421
|
+
"enum": [
|
|
6422
|
+
"dev",
|
|
6423
|
+
"staging",
|
|
6424
|
+
"prod"
|
|
6425
|
+
],
|
|
5306
6426
|
"description": "Target environment. One of the project's configured envs (`dev`, `stage`, `prod`)."
|
|
5307
6427
|
}
|
|
5308
6428
|
},
|
|
5309
|
-
"required": [
|
|
6429
|
+
"required": [
|
|
6430
|
+
"env"
|
|
6431
|
+
],
|
|
5310
6432
|
"additionalProperties": false,
|
|
5311
6433
|
"description": "Body for `POST /api/admin/configs/{id}/publish` and `DELETE /api/admin/configs/{id}/drafts`. Names the target env."
|
|
5312
6434
|
},
|
|
@@ -5318,7 +6440,9 @@
|
|
|
5318
6440
|
"const": true
|
|
5319
6441
|
}
|
|
5320
6442
|
},
|
|
5321
|
-
"required": [
|
|
6443
|
+
"required": [
|
|
6444
|
+
"ok"
|
|
6445
|
+
],
|
|
5322
6446
|
"additionalProperties": false
|
|
5323
6447
|
},
|
|
5324
6448
|
"PublishConfigDraftRequest": {
|
|
@@ -5326,11 +6450,17 @@
|
|
|
5326
6450
|
"properties": {
|
|
5327
6451
|
"env": {
|
|
5328
6452
|
"type": "string",
|
|
5329
|
-
"enum": [
|
|
6453
|
+
"enum": [
|
|
6454
|
+
"dev",
|
|
6455
|
+
"staging",
|
|
6456
|
+
"prod"
|
|
6457
|
+
],
|
|
5330
6458
|
"description": "Target environment. One of the project's configured envs (`dev`, `stage`, `prod`)."
|
|
5331
6459
|
}
|
|
5332
6460
|
},
|
|
5333
|
-
"required": [
|
|
6461
|
+
"required": [
|
|
6462
|
+
"env"
|
|
6463
|
+
],
|
|
5334
6464
|
"additionalProperties": false,
|
|
5335
6465
|
"description": "Body for `POST /api/admin/configs/{id}/publish` and `DELETE /api/admin/configs/{id}/drafts`. Names the target env."
|
|
5336
6466
|
},
|
|
@@ -5342,7 +6472,11 @@
|
|
|
5342
6472
|
},
|
|
5343
6473
|
"env": {
|
|
5344
6474
|
"type": "string",
|
|
5345
|
-
"enum": [
|
|
6475
|
+
"enum": [
|
|
6476
|
+
"dev",
|
|
6477
|
+
"staging",
|
|
6478
|
+
"prod"
|
|
6479
|
+
],
|
|
5346
6480
|
"description": "Target environment. One of the project's configured envs (`dev`, `stage`, `prod`)."
|
|
5347
6481
|
},
|
|
5348
6482
|
"version": {
|
|
@@ -5352,7 +6486,11 @@
|
|
|
5352
6486
|
"description": "Newly published version on `env`."
|
|
5353
6487
|
}
|
|
5354
6488
|
},
|
|
5355
|
-
"required": [
|
|
6489
|
+
"required": [
|
|
6490
|
+
"id",
|
|
6491
|
+
"env",
|
|
6492
|
+
"version"
|
|
6493
|
+
],
|
|
5356
6494
|
"additionalProperties": false
|
|
5357
6495
|
},
|
|
5358
6496
|
"ListConfigActivityResponse": {
|
|
@@ -5372,7 +6510,11 @@
|
|
|
5372
6510
|
},
|
|
5373
6511
|
"actorType": {
|
|
5374
6512
|
"type": "string",
|
|
5375
|
-
"enum": [
|
|
6513
|
+
"enum": [
|
|
6514
|
+
"user",
|
|
6515
|
+
"cli",
|
|
6516
|
+
"system"
|
|
6517
|
+
]
|
|
5376
6518
|
},
|
|
5377
6519
|
"payload": {
|
|
5378
6520
|
"anyOf": [
|
|
@@ -5387,7 +6529,14 @@
|
|
|
5387
6529
|
"description": "ISO-8601 timestamp."
|
|
5388
6530
|
}
|
|
5389
6531
|
},
|
|
5390
|
-
"required": [
|
|
6532
|
+
"required": [
|
|
6533
|
+
"id",
|
|
6534
|
+
"action",
|
|
6535
|
+
"actorEmail",
|
|
6536
|
+
"actorType",
|
|
6537
|
+
"payload",
|
|
6538
|
+
"createdAt"
|
|
6539
|
+
],
|
|
5391
6540
|
"additionalProperties": false
|
|
5392
6541
|
},
|
|
5393
6542
|
"description": "Recent audit rows for one config, newest first."
|
|
@@ -5450,14 +6599,28 @@
|
|
|
5450
6599
|
"description": "ISO-8601 publish timestamp for this version."
|
|
5451
6600
|
}
|
|
5452
6601
|
},
|
|
5453
|
-
"required": [
|
|
6602
|
+
"required": [
|
|
6603
|
+
"value",
|
|
6604
|
+
"version",
|
|
6605
|
+
"publishedAt"
|
|
6606
|
+
],
|
|
5454
6607
|
"additionalProperties": false
|
|
5455
6608
|
},
|
|
5456
|
-
"required": [
|
|
6609
|
+
"required": [
|
|
6610
|
+
"dev",
|
|
6611
|
+
"staging",
|
|
6612
|
+
"prod"
|
|
6613
|
+
],
|
|
5457
6614
|
"description": "Per-env latest value, switches, version, and publish timestamp."
|
|
5458
6615
|
}
|
|
5459
6616
|
},
|
|
5460
|
-
"required": [
|
|
6617
|
+
"required": [
|
|
6618
|
+
"id",
|
|
6619
|
+
"name",
|
|
6620
|
+
"description",
|
|
6621
|
+
"updatedAt",
|
|
6622
|
+
"envs"
|
|
6623
|
+
],
|
|
5461
6624
|
"additionalProperties": false
|
|
5462
6625
|
}
|
|
5463
6626
|
},
|
|
@@ -5472,7 +6635,10 @@
|
|
|
5472
6635
|
]
|
|
5473
6636
|
}
|
|
5474
6637
|
},
|
|
5475
|
-
"required": [
|
|
6638
|
+
"required": [
|
|
6639
|
+
"data",
|
|
6640
|
+
"next_cursor"
|
|
6641
|
+
],
|
|
5476
6642
|
"additionalProperties": false
|
|
5477
6643
|
},
|
|
5478
6644
|
"GetKillswitchResponse": {
|
|
@@ -5528,14 +6694,28 @@
|
|
|
5528
6694
|
"description": "ISO-8601 publish timestamp for this version."
|
|
5529
6695
|
}
|
|
5530
6696
|
},
|
|
5531
|
-
"required": [
|
|
6697
|
+
"required": [
|
|
6698
|
+
"value",
|
|
6699
|
+
"version",
|
|
6700
|
+
"publishedAt"
|
|
6701
|
+
],
|
|
5532
6702
|
"additionalProperties": false
|
|
5533
6703
|
},
|
|
5534
|
-
"required": [
|
|
6704
|
+
"required": [
|
|
6705
|
+
"dev",
|
|
6706
|
+
"staging",
|
|
6707
|
+
"prod"
|
|
6708
|
+
],
|
|
5535
6709
|
"description": "Per-env latest value, switches, version, and publish timestamp."
|
|
5536
6710
|
}
|
|
5537
6711
|
},
|
|
5538
|
-
"required": [
|
|
6712
|
+
"required": [
|
|
6713
|
+
"id",
|
|
6714
|
+
"name",
|
|
6715
|
+
"description",
|
|
6716
|
+
"updatedAt",
|
|
6717
|
+
"envs"
|
|
6718
|
+
],
|
|
5539
6719
|
"additionalProperties": false
|
|
5540
6720
|
},
|
|
5541
6721
|
"CreateKillswitchRequest": {
|
|
@@ -5551,6 +6731,19 @@
|
|
|
5551
6731
|
"type": "string",
|
|
5552
6732
|
"maxLength": 512
|
|
5553
6733
|
},
|
|
6734
|
+
"folder": {
|
|
6735
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
6736
|
+
"anyOf": [
|
|
6737
|
+
{
|
|
6738
|
+
"type": "string",
|
|
6739
|
+
"maxLength": 256,
|
|
6740
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
6741
|
+
},
|
|
6742
|
+
{
|
|
6743
|
+
"type": "null"
|
|
6744
|
+
}
|
|
6745
|
+
]
|
|
6746
|
+
},
|
|
5554
6747
|
"value": {
|
|
5555
6748
|
"description": "Default value applied to every env at creation. Defaults to `false`. Use `true` to ship the killswitch pre-tripped.",
|
|
5556
6749
|
"type": "boolean"
|
|
@@ -5563,7 +6756,9 @@
|
|
|
5563
6756
|
}
|
|
5564
6757
|
}
|
|
5565
6758
|
},
|
|
5566
|
-
"required": [
|
|
6759
|
+
"required": [
|
|
6760
|
+
"name"
|
|
6761
|
+
],
|
|
5567
6762
|
"additionalProperties": false,
|
|
5568
6763
|
"description": "Body for `POST /api/admin/killswitches`. Only `name` is required."
|
|
5569
6764
|
},
|
|
@@ -5580,7 +6775,10 @@
|
|
|
5580
6775
|
"description": "Stable config key in `folder.name` form (two lowercase segments separated by a dot, e.g. `pricing.tiers`). Used by SDKs as `Shipeasy.getConfig('<name>')`. Immutable after create."
|
|
5581
6776
|
}
|
|
5582
6777
|
},
|
|
5583
|
-
"required": [
|
|
6778
|
+
"required": [
|
|
6779
|
+
"id",
|
|
6780
|
+
"name"
|
|
6781
|
+
],
|
|
5584
6782
|
"additionalProperties": false
|
|
5585
6783
|
},
|
|
5586
6784
|
"UpdateKillswitchRequest": {
|
|
@@ -5598,6 +6796,19 @@
|
|
|
5598
6796
|
}
|
|
5599
6797
|
]
|
|
5600
6798
|
},
|
|
6799
|
+
"folder": {
|
|
6800
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
6801
|
+
"anyOf": [
|
|
6802
|
+
{
|
|
6803
|
+
"type": "string",
|
|
6804
|
+
"maxLength": 256,
|
|
6805
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
6806
|
+
},
|
|
6807
|
+
{
|
|
6808
|
+
"type": "null"
|
|
6809
|
+
}
|
|
6810
|
+
]
|
|
6811
|
+
},
|
|
5601
6812
|
"value": {
|
|
5602
6813
|
"description": "Flat value applied to every env. Publishes a new version per env when set. Omit to leave values unchanged.",
|
|
5603
6814
|
"type": "boolean"
|
|
@@ -5621,7 +6832,9 @@
|
|
|
5621
6832
|
"description": "Killswitch id that was updated."
|
|
5622
6833
|
}
|
|
5623
6834
|
},
|
|
5624
|
-
"required": [
|
|
6835
|
+
"required": [
|
|
6836
|
+
"id"
|
|
6837
|
+
],
|
|
5625
6838
|
"additionalProperties": false
|
|
5626
6839
|
},
|
|
5627
6840
|
"DeleteKillswitchResponse": {
|
|
@@ -5632,7 +6845,9 @@
|
|
|
5632
6845
|
"const": true
|
|
5633
6846
|
}
|
|
5634
6847
|
},
|
|
5635
|
-
"required": [
|
|
6848
|
+
"required": [
|
|
6849
|
+
"ok"
|
|
6850
|
+
],
|
|
5636
6851
|
"additionalProperties": false
|
|
5637
6852
|
},
|
|
5638
6853
|
"SetKillswitchSwitchRequest": {
|
|
@@ -5640,7 +6855,11 @@
|
|
|
5640
6855
|
"properties": {
|
|
5641
6856
|
"env": {
|
|
5642
6857
|
"type": "string",
|
|
5643
|
-
"enum": [
|
|
6858
|
+
"enum": [
|
|
6859
|
+
"dev",
|
|
6860
|
+
"staging",
|
|
6861
|
+
"prod"
|
|
6862
|
+
],
|
|
5644
6863
|
"description": "Target environment (`dev`/`stage`/`prod`)."
|
|
5645
6864
|
},
|
|
5646
6865
|
"switchKey": {
|
|
@@ -5654,7 +6873,11 @@
|
|
|
5654
6873
|
"description": "New boolean value for this `switchKey` on this `env`."
|
|
5655
6874
|
}
|
|
5656
6875
|
},
|
|
5657
|
-
"required": [
|
|
6876
|
+
"required": [
|
|
6877
|
+
"env",
|
|
6878
|
+
"switchKey",
|
|
6879
|
+
"value"
|
|
6880
|
+
],
|
|
5658
6881
|
"additionalProperties": false,
|
|
5659
6882
|
"description": "Body for `PUT /api/admin/killswitches/{id}/switch`. Sets or updates one switch entry on one env."
|
|
5660
6883
|
},
|
|
@@ -5666,7 +6889,11 @@
|
|
|
5666
6889
|
},
|
|
5667
6890
|
"env": {
|
|
5668
6891
|
"type": "string",
|
|
5669
|
-
"enum": [
|
|
6892
|
+
"enum": [
|
|
6893
|
+
"dev",
|
|
6894
|
+
"staging",
|
|
6895
|
+
"prod"
|
|
6896
|
+
],
|
|
5670
6897
|
"description": "Target environment. One of the project's configured envs (`dev`, `stage`, `prod`)."
|
|
5671
6898
|
},
|
|
5672
6899
|
"switchKey": {
|
|
@@ -5679,7 +6906,12 @@
|
|
|
5679
6906
|
"type": "boolean"
|
|
5680
6907
|
}
|
|
5681
6908
|
},
|
|
5682
|
-
"required": [
|
|
6909
|
+
"required": [
|
|
6910
|
+
"id",
|
|
6911
|
+
"env",
|
|
6912
|
+
"switchKey",
|
|
6913
|
+
"value"
|
|
6914
|
+
],
|
|
5683
6915
|
"additionalProperties": false
|
|
5684
6916
|
},
|
|
5685
6917
|
"UnsetKillswitchSwitchRequest": {
|
|
@@ -5687,7 +6919,11 @@
|
|
|
5687
6919
|
"properties": {
|
|
5688
6920
|
"env": {
|
|
5689
6921
|
"type": "string",
|
|
5690
|
-
"enum": [
|
|
6922
|
+
"enum": [
|
|
6923
|
+
"dev",
|
|
6924
|
+
"staging",
|
|
6925
|
+
"prod"
|
|
6926
|
+
],
|
|
5691
6927
|
"description": "Target environment."
|
|
5692
6928
|
},
|
|
5693
6929
|
"switchKey": {
|
|
@@ -5697,7 +6933,10 @@
|
|
|
5697
6933
|
"description": "Switch key to remove."
|
|
5698
6934
|
}
|
|
5699
6935
|
},
|
|
5700
|
-
"required": [
|
|
6936
|
+
"required": [
|
|
6937
|
+
"env",
|
|
6938
|
+
"switchKey"
|
|
6939
|
+
],
|
|
5701
6940
|
"additionalProperties": false,
|
|
5702
6941
|
"description": "Body for `DELETE /api/admin/killswitches/{id}/switch`. Removes one switch entry from one env."
|
|
5703
6942
|
},
|
|
@@ -5709,7 +6948,11 @@
|
|
|
5709
6948
|
},
|
|
5710
6949
|
"env": {
|
|
5711
6950
|
"type": "string",
|
|
5712
|
-
"enum": [
|
|
6951
|
+
"enum": [
|
|
6952
|
+
"dev",
|
|
6953
|
+
"staging",
|
|
6954
|
+
"prod"
|
|
6955
|
+
],
|
|
5713
6956
|
"description": "Target environment. One of the project's configured envs (`dev`, `stage`, `prod`)."
|
|
5714
6957
|
},
|
|
5715
6958
|
"switchKey": {
|
|
@@ -5723,7 +6966,12 @@
|
|
|
5723
6966
|
"description": "`true` if the entry existed and was removed, `false` if no-op."
|
|
5724
6967
|
}
|
|
5725
6968
|
},
|
|
5726
|
-
"required": [
|
|
6969
|
+
"required": [
|
|
6970
|
+
"id",
|
|
6971
|
+
"env",
|
|
6972
|
+
"switchKey",
|
|
6973
|
+
"removed"
|
|
6974
|
+
],
|
|
5727
6975
|
"additionalProperties": false
|
|
5728
6976
|
},
|
|
5729
6977
|
"ListUniversesResponse": {
|
|
@@ -5740,8 +6988,9 @@
|
|
|
5740
6988
|
},
|
|
5741
6989
|
"name": {
|
|
5742
6990
|
"type": "string",
|
|
5743
|
-
"
|
|
5744
|
-
"
|
|
6991
|
+
"maxLength": 128,
|
|
6992
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
6993
|
+
"description": "Stable universe key. Single segment or `folder.name`. Lowercase letters, digits, `_` or `-`; max 128 chars. Immutable after create."
|
|
5745
6994
|
},
|
|
5746
6995
|
"unitType": {
|
|
5747
6996
|
"type": "string",
|
|
@@ -5771,7 +7020,13 @@
|
|
|
5771
7020
|
"description": "ISO-8601 timestamp of creation."
|
|
5772
7021
|
}
|
|
5773
7022
|
},
|
|
5774
|
-
"required": [
|
|
7023
|
+
"required": [
|
|
7024
|
+
"id",
|
|
7025
|
+
"name",
|
|
7026
|
+
"unitType",
|
|
7027
|
+
"holdoutRange",
|
|
7028
|
+
"createdAt"
|
|
7029
|
+
],
|
|
5775
7030
|
"additionalProperties": false
|
|
5776
7031
|
}
|
|
5777
7032
|
},
|
|
@@ -5786,7 +7041,10 @@
|
|
|
5786
7041
|
]
|
|
5787
7042
|
}
|
|
5788
7043
|
},
|
|
5789
|
-
"required": [
|
|
7044
|
+
"required": [
|
|
7045
|
+
"data",
|
|
7046
|
+
"next_cursor"
|
|
7047
|
+
],
|
|
5790
7048
|
"additionalProperties": false
|
|
5791
7049
|
},
|
|
5792
7050
|
"CreateUniverseRequest": {
|
|
@@ -5794,8 +7052,22 @@
|
|
|
5794
7052
|
"properties": {
|
|
5795
7053
|
"name": {
|
|
5796
7054
|
"type": "string",
|
|
5797
|
-
"
|
|
5798
|
-
"
|
|
7055
|
+
"maxLength": 128,
|
|
7056
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
7057
|
+
"description": "Stable universe key. Single segment or `folder.name`. Lowercase letters, digits, `_` or `-`; max 128 chars. Immutable after create."
|
|
7058
|
+
},
|
|
7059
|
+
"folder": {
|
|
7060
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
7061
|
+
"anyOf": [
|
|
7062
|
+
{
|
|
7063
|
+
"type": "string",
|
|
7064
|
+
"maxLength": 256,
|
|
7065
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
7066
|
+
},
|
|
7067
|
+
{
|
|
7068
|
+
"type": "null"
|
|
7069
|
+
}
|
|
7070
|
+
]
|
|
5799
7071
|
},
|
|
5800
7072
|
"unit_type": {
|
|
5801
7073
|
"default": "user_id",
|
|
@@ -5827,7 +7099,11 @@
|
|
|
5827
7099
|
"description": "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."
|
|
5828
7100
|
}
|
|
5829
7101
|
},
|
|
5830
|
-
"required": [
|
|
7102
|
+
"required": [
|
|
7103
|
+
"name",
|
|
7104
|
+
"unit_type",
|
|
7105
|
+
"holdout_range"
|
|
7106
|
+
],
|
|
5831
7107
|
"additionalProperties": false,
|
|
5832
7108
|
"description": "Body for `POST /api/admin/universes`. Only `name` is required."
|
|
5833
7109
|
},
|
|
@@ -5840,16 +7116,33 @@
|
|
|
5840
7116
|
},
|
|
5841
7117
|
"name": {
|
|
5842
7118
|
"type": "string",
|
|
5843
|
-
"
|
|
5844
|
-
"
|
|
7119
|
+
"maxLength": 128,
|
|
7120
|
+
"pattern": "^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$",
|
|
7121
|
+
"description": "Stable universe key. Single segment or `folder.name`. Lowercase letters, digits, `_` or `-`; max 128 chars. Immutable after create."
|
|
5845
7122
|
}
|
|
5846
7123
|
},
|
|
5847
|
-
"required": [
|
|
7124
|
+
"required": [
|
|
7125
|
+
"id",
|
|
7126
|
+
"name"
|
|
7127
|
+
],
|
|
5848
7128
|
"additionalProperties": false
|
|
5849
7129
|
},
|
|
5850
7130
|
"UpdateUniverseRequest": {
|
|
5851
7131
|
"type": "object",
|
|
5852
7132
|
"properties": {
|
|
7133
|
+
"folder": {
|
|
7134
|
+
"description": "Optional folder name used to group items in the dashboard. Part of the SDK lookup key: an item in folder `checkout` named `new-cart` is referenced as `checkout/new-cart` from the SDK.",
|
|
7135
|
+
"anyOf": [
|
|
7136
|
+
{
|
|
7137
|
+
"type": "string",
|
|
7138
|
+
"maxLength": 256,
|
|
7139
|
+
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
7140
|
+
},
|
|
7141
|
+
{
|
|
7142
|
+
"type": "null"
|
|
7143
|
+
}
|
|
7144
|
+
]
|
|
7145
|
+
},
|
|
5853
7146
|
"holdout_range": {
|
|
5854
7147
|
"anyOf": [
|
|
5855
7148
|
{
|
|
@@ -5885,7 +7178,9 @@
|
|
|
5885
7178
|
"description": "Universe id that was updated."
|
|
5886
7179
|
}
|
|
5887
7180
|
},
|
|
5888
|
-
"required": [
|
|
7181
|
+
"required": [
|
|
7182
|
+
"id"
|
|
7183
|
+
],
|
|
5889
7184
|
"additionalProperties": false
|
|
5890
7185
|
},
|
|
5891
7186
|
"DeleteUniverseResponse": {
|
|
@@ -5896,7 +7191,9 @@
|
|
|
5896
7191
|
"const": true
|
|
5897
7192
|
}
|
|
5898
7193
|
},
|
|
5899
|
-
"required": [
|
|
7194
|
+
"required": [
|
|
7195
|
+
"ok"
|
|
7196
|
+
],
|
|
5900
7197
|
"additionalProperties": false
|
|
5901
7198
|
}
|
|
5902
7199
|
},
|