Promotes one variant to the whole rollout and records who decided.
Promotes one variant to the whole rollout and records who decided.
POST /v1/experiment/{id}/decide
| Address | https://api.hanzo.ai/v1/experiment/{id}/decide |
| Method | POST |
| Operation | post_experiment_by_id_decide |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Promotes one variant to the whole rollout and records who decided.
It rewrites the assignment flag so the named winner serves 100% of the rollout and every other arm 0%, preserving the flag's targeting groups and payloads, then stamps the experiment decided with the winner, the deciding credential and the time. This is a production behaviour change that takes effect immediately for every subject the flag evaluates.
It requires an ORG ADMIN of the caller's own org — a stricter gate than the rest of this surface, matching the flags write plane, because promoting is a flag write. The admin check runs AFTER the experiment is found, so a caller from another tenant is answered not-found rather than forbidden and learns nothing about what exists.
An experiment whose assignment flag has gone missing is a conflict rather than a silent no-op — there is nothing to promote.
Deciding is NOT terminal. A second call re-promotes a different variant and re-stamps the row; the status stays decided and the previous winner is overwritten with no record that it was ever chosen. Nothing here reverts the flag to its original weights either, so an experiment cannot be un-decided through this route — restoring a split means writing the flag definition back through the flags plane.
Request
2 fields, body application/json (required).
| Field | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
winner | body | string | yes | Winner is the variant to promote. |
Response
| Status | Body | Meaning |
|---|---|---|
200 | Trial | ok |
200 body — 18 fields.
| Field | In | Type | Always | Description |
|---|---|---|---|---|
createdAt | body | string | — | when it started assigning |
createdBy | body | string | — | the credential that registered it |
decidedAt | body | string | — | when the promotion took effect |
decidedBy | body | string | — | the credential that promoted the winner |
exposureEvent | body | string | — | the event that enrols a subject — the analysis denominator |
flagKey | body | string | — | the assignment flag this experiment drives |
id | body | string | — | the experiment's slug, unique within the project |
metricEvent | body | string | — | the event that counts as a conversion — the numerator |
name | body | string | — | free text for a reader |
project | body | string | — | the sub-scope within the org, stamped from the principal |
status | body | string | — | running while it assigns and measures, decided once a winner is promoted |
subjectKind | body | string | — | the unit assigned and measured: user, org, session or audience |
variants | body | Arm[] | — | the arms, weighted, one of them the control |
variants[].control | body | boolean | — | true on the baseline arm every other arm is compared to |
variants[].key | body | string | — | the arm's slug, unique within the experiment |
variants[].payload | body | any | — | opaque JSON the arm carries, which the consumer interprets |
variants[].weight | body | number | — | its share of the rollout; the arms sum to 100 |
winner | body | string | — | the arm promoted to the whole rollout |
Failure carries the platform error shape — see Errors.
Examples
hanzo experiments decide <id> --winner <winner>import { Configuration, ExperimentApi } from 'hanzoai';
const api = new ExperimentApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postExperimentByIdDecide({ id: 'id', winner: "<winner>" });from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import ExperimentApi
client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = ExperimentApi(client).post_experiment_by_id_decide(id='id', winner="<winner>")cfg := cloud.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := cloud.NewAPIClient(cfg)
resp, _, err := client.ExperimentAPI.PostExperimentByIdDecide(context.Background()).Execute()
if err != nil {
return err
}use hanzo_cloud::apis::{configuration::Configuration, experiment_api};
let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();
let result = experiment_api::post_experiment_by_id_decide(&cfg, Default::default()).await?;import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.ExperimentApi;
ApiClient client = new ApiClient();
client.setRequestInterceptor(b -> b.header("Authorization", "Bearer " + System.getenv("HANZO_API_KEY")));
var result = new ExperimentApi(client).postExperimentByIdDecide();The method above is the one at the current release of the document. [email protected] (npm) and [email protected] (PyPI) were generated from an earlier release, where this operation carried a different id, so it spells the method differently — regenerating the clients is what makes the two agree. SDKs →
curl -X POST https://api.hanzo.ai/v1/experiment/<id>/decide \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"winner": "<winner>"
}'The door reaches experiment through the experiments tool, which names its 7 operations with its own verbs — this one among them, under a name only the door declares. describe explains any of them:
curl -X POST https://api.hanzo.ai/v1/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe",
"arguments": {
"op": "list_experiments"
}
}
}'How is this guide?