Update an A/B experiment
Move an experiment through its lifecycle, or change its traffic split.
Move an experiment through its lifecycle, or change its traffic split.
Supported transitions::
draft -> active start splitting live traffic active -> paused stop splitting, keep the record active | paused -> concluded close the experiment
Three state rules, all answered with 409 (code 1201):
- Only one experiment per control agent may be ACTIVE. Conclude or pause the running one before activating another.
winneris only accepted once the experiment is concluded. Setting the winner on an active experiment is a 409 — but{"status": "concluded", "winner": "variant"}in a single request is legal and is the normal way to close an experiment.- An ACTIVE experiment cannot be deleted (see
DELETE).
Promoting the variant: set variant_traffic_pct to 100. Every call
against the control agent then routes to the variant, and nothing else has to
change — campaigns, batches and scheduled calls keep naming the control
agent, so there is no re-targeting step and no window in which some calls use
the old agent. Conversely 0 parks the variant without ending the
experiment.
Nothing can be cleared. The update is applied with null-exclusion
upstream, so a field sent as null would be discarded and the response
would look like a successful no-op. This API rejects an explicit null with
400 instead; in particular a winner cannot be un-set once recorded.
Rate limit: 1000 requests per minute per organization (bucket default). Exceeding it returns 429 with Retry-After; the X-RateLimit-* response headers report your remaining allowance on every call.
v2/agents/{agent_id}/versions/{version_id}Authorization
AuthorizationRequiredBearer <token>
Your Graine API key. Create one in the dashboard under Developers, or via POST /v2/api-keys. Send it as Authorization: Bearer <key>.
In: header
Request Body
application/jsonRequiredversion_nameVersion Name | null
New experiment name.
100descriptionDescription | null
New notes.
500variable_testedVariable Tested | null
New label for what is being tested.
200variant_traffic_pctVariant Traffic Pct | null
New traffic split. 0 sends every call to the control agent; 100 sends every call to the variant, which is how a variant is promoted.
0Maximum: 100statusStatus | null
draft | active | paused | concluded
winnerWinner | null
control | variant. Only accepted when the experiment is, or is becoming in this same request, concluded.
start_dateStart Date | null
ISO-8601 timestamp with a timezone offset. Informational.
end_dateEnd Date | null
ISO-8601 timestamp with a timezone offset. Informational.
Path Parameters
agent_idRequiredAgent Id
The CONTROL agent.
version_idRequiredVersion Id
Experiment identifier.
Query Parameters
organization_idOrganization Id
Must match the organisation the API key belongs to.
Response Body
200
The updated experiment.
version_idRequiredVersion Id
Experiment identifier.
main_agent_idRequiredMain Agent Id
The CONTROL agent. Always equal to the agent_id in the path.
variant_agent_idRequiredVariant Agent Id
The CHALLENGER agent that receives the split traffic.
version_nameRequiredVersion Name
Experiment name.
descriptionDescription | null
Free-text notes about the experiment.
variable_testedVariable Tested | null
What is being tested, e.g. 'voice', 'script', 'cadence'.
variant_traffic_pctRequiredVariant Traffic Pct
Percentage of calls routed to the variant (0-100). The remainder goes to the control agent. 0 pauses the variant in place; 100 promotes it.
statusRequiredStatus
draft | active | paused | concluded
winnerWinner | null
control | variant. Only ever set on a concluded experiment.
start_dateStart Date | null
ISO-8601 UTC. Informational; it does not gate routing.
end_dateEnd Date | null
ISO-8601 UTC. Informational; it does not gate routing.
created_byCreated By | null
Identifier of whoever created the experiment.
created_atCreated At | null
ISO-8601 UTC.
updated_atUpdated At | null
ISO-8601 UTC.
400
1000 — malformed or contradictory input: an unknown status token, an empty patch body, an explicit null, or a variant agent that does not exist in this organisation.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
401
1100 — missing, unknown or inactive API key. 1101 — a browser session token was presented.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
403
1102 — the key is valid but lacks the scope this endpoint requires, or names another organisation. GET /v2/scopes reports which scopes the key holds.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
404
1200 — no such agent, or no such version for that agent, in this organisation. Cross-tenant reads answer 404, never 403, so ids cannot be probed.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
409
1201 — the experiment's state does not allow this action: a second ACTIVE version for the same control agent, a DELETE against an ACTIVE version, or a winner set before the experiment is concluded.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
422
1001 — the body or query failed validation; the message names the first offending field.
errorRequiredinteger
Stable integer code from the error table. Branch on this, not on the message.
messageRequiredstring
One human-readable sentence. Wording may change; the code will not.
429
1300 — per-organisation rate limit exceeded. Carries Retry-After.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
503
1501 — the agent service is unreachable or returned a 5xx.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
504
1502 — the agent service did not respond in time.
errorRequiredError
Stable integer code from the /v2 error table. Branch on this.
messageRequiredMessage
One human-readable sentence. Wording may change; the code will not.
The updated experiment.

