/v1/contextual-bandit-queries— the assignment SQL plus the targeting (context) columns the bandit splits on. This is the bandit-specific replacement for borrowing an Experiment Assignment Query off the datasource./v1/contextual-bandits— the bandit itself, which references a query by id.
Contextual Bandits are an Enterprise-only feature. Every endpoint below returns
402 Plan Does Not Allow on Pro / Free plans.1. Create a Contextual Bandit Query
A Contextual Bandit needs a query that defines the assignment SQL and the targeting-attribute columns it splits on.targetingAttributeColumns is required and must be non-empty — a bandit with no context to split on is not a contextual bandit. Each named column must also appear in the query’s SELECT. The query should also select the leaf_id, bandit_version, and variation_weights columns logged by your tracking callback — without them the SRM health check is skipped.
cbq_…). You can manage queries with the standard CRUD endpoints (GET /v1/contextual-bandit-queries, GET/PUT/DELETE /v1/contextual-bandit-queries/:id); pass ?datasourceId=ds_abc on the list endpoint to scope by datasource.
2. Create the Contextual Bandit
Reference the query from the previous step viacontextualBanditQueryId.
name, trackingKey, datasource, contextualBanditQueryId, variations, decisionMetric, and contextualAttributes. Other fields (hashAttribute, queryFilter, activationMetric, minUsersPerLeaf, maxLeaves, etc.) are optional and fall back to defaults.
The response includes the new Contextual Bandit id (cb_…). The CB is provisioned in status: "draft" with an empty currentLeafWeights array at the document root; it stays empty until the first successful refresh.
3. Link a Feature Flag
A Contextual Bandit serves its variations through acontextual-bandit-ref rule on a Feature Flag, and it needs at least one linked Feature Flag before it can start. Create the flag first with POST /v2/features, then link it:
variations must cover every Contextual Bandit variation exactly once — variationId is the id of each entry in the CB’s variations array, not its key. Targeting (condition, saved groups, prerequisites, coverage) lives on the Contextual Bandit and is inherited by the rule, so those fields are not accepted here.
The rule is appended to the bottom of the flag’s rule list in a new draft revision, which auto-publishes when you start the Contextual Bandit. Pass "autoPublish": true to publish it right away, or "draftVersion": 7 to add the rule to an existing draft instead of starting a new one. By default the rule applies to every environment; pass "allEnvironments": false with "environments": ["production"] to narrow it.
Response:
GET /v1/contextual-bandits/:id/linked-features— the linked flags enriched with live/draft state, per-environment rule state, and variation values (the same payload the CB detail page renders).DELETE /v1/contextual-bandits/:id/linked-feature/:featureId— removes everycontextual-bandit-refrule pointing at this bandit from the flag and drops the linkage. Like the POST, the removal lands in a draft unless you pass?autoPublish=true. When the flag has no such rule left, only the linkage is cleared.
4. Start the Contextual Bandit
Move the CB out ofdraft (to status: "running") so it is eligible for refresh:
{ "contextualBandit": { … } }.
5. Refresh — run a snapshot
Triggers the contextual-bandit snapshot pipeline. The orchestrator builds frozen settings, opens a ContextualBanditSnapshot (CBS) doc, runs the warehouse query and the stats engine, and on success persists a ContextualBanditEvent (CBE) with the new per-leaf weights. Each successful snapshot increments the CB’sbanditVersion.
cbeId is omitted when the run failed before producing an event (the CBS doc will be in status: "error").
6. Read the latest results
Returns the same payload the GrowthBook UI uses to render the CB results table — the latest stats engine output plus a snapshot-status summary.contextualBanditSnapshot and latest are each null until a run exists):
latest.status is one of running, success, or error, and latest.runStarted may be null if the run hasn’t started.
Use the companion endpoints for finer-grained inspection:
GET /v1/contextual-bandits/:id/snapshots— list recent snapshot runs (optional?limit=, max 100).GET /v1/contextual-bandits/:id/snapshots/:snapshotId— single snapshot status.GET /v1/contextual-bandits/:id/events— list CBE outputs, one per successful snapshot (optional?limit=, max 100).GET /v1/contextual-bandits/:id/events/:eventId— single CBE.GET /v1/contextual-bandits/:id/current— current root-levelcurrentLeafWeightsplus the latest event object (latestEvent, ornull).
/current response looks like:
7. Stop the Contextual Bandit
When you’re done, stop the CB:start, this returns the updated CB under contextualBandit.
Standard CRUD
Both resources also expose the default CRUD endpoints:GET /v1/contextual-bandits(filter with?projectId=,?datasourceId=, or?trackingKey=),GET /v1/contextual-bandits/:id,POST /v1/contextual-bandits,PUT /v1/contextual-bandits/:id,DELETE /v1/contextual-bandits/:id.GET /v1/contextual-bandit-queries(filter with?datasourceId=),GET /v1/contextual-bandit-queries/:id,POST /v1/contextual-bandit-queries,PUT /v1/contextual-bandit-queries/:id,DELETE /v1/contextual-bandit-queries/:id.
Permissions cheat sheet
Permissions are checked directly against the Contextual Bandit doc (CBs no longer delegate RBAC to a paired experiment):- Read (
GET results,GET current,GET snapshot(s),GET event(s),GET /:id,GET /) —canReadSingleProjectResource(cb.project). - Create (
POST /) —canCreateContextualBandit(cb). - Update (
PUT /:id) —canUpdateContextualBandit(existing, updated). - Run (
POST refresh,POST start,POST stop) —canRunContextualBandit(cb, environments). - Delete (
DELETE /:id) —canDeleteContextualBandit(cb). - Link / unlink a Feature Flag (
POST/DELETE /:id/linked-feature/:featureId) —canUpdateContextualBanditon the bandit, pluscanUpdateFeature,canManageFeatureDrafts, andcanPublishFeature(scoped to the rule’s environments) on the Feature Flag.
canUpdateDataSourceSettings on the query’s datasource.
Plan gate (hasPremiumFeature("contextual-bandits")) is checked first on every endpoint and short-circuits with 402 before any data access.
