API reference
Experiments
Experiments endpoints.
| Method | Path | Summary |
|---|---|---|
GET | /v1/account/experiments | The account’s experiments, newest first |
POST | /v1/account/experiments | Plan an experiment: two or three published versions of one playbook on a number assignment, a route of a number’s schedule or a widget key, a split, a target metric chosen in advance, a minimum sample and an end date |
GET | /v1/account/experiments/{experimentId} | One experiment and its results per arm: every catalogue metric with n and its interval, and verdicts against the control; the target metric’s is labelled tested once every arm has its sample |
POST | /v1/account/experiments/{experimentId}/start | Start splitting traffic. Every arm’s effective playbook for the group is computed first; the start is refused if one needs review |
POST | /v1/account/experiments/{experimentId}/stop | Stop an experiment now. Its traffic goes back to the usual version, and its results so far are kept |
The account’s experiments, newest first#
GET /v1/account/experiments
Authentication: Bearer token: Authorization: Bearer <token> (Supabase access token). Bearer token: Authorization: Bearer <token> (An API token (ans_pat_ or ans_svc_). Only routes that list a scope here accept one, and only with that scope.).
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
status | enum | No | One of: "draft", "running", "stopped", "completed". |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
experiments | array<Experiment> | Yes | — |
experiments[].arms | array<object> | Yes | — |
experiments[].arms[].arm | enum | Yes | One of: "A", "B", "C". |
experiments[].arms[].playbookVersionId | string (pbv_… ID) | Yes | ID (pbv_…) |
experiments[].arms[].version | number | null | Yes | — |
experiments[].arms[].weight | number | Yes | — |
experiments[].createdAt | string (date-time) | Yes | — |
experiments[].endReason | enum | null | Yes | One of: "ended", "sample_reached", "manual", "new_version_published", "version_archived", "playbook_archived", "scope_changed". |
experiments[].endedAt | string (date-time) | null | Yes | — |
experiments[].endsAt | string (date-time) | Yes | — |
experiments[].groupId | string (grp_… ID) | Yes | ID (grp_…) |
experiments[].groupName | string | null | Yes | — |
experiments[].id | string (exp_… ID) | Yes | ID (exp_…) |
experiments[].minSample | number | Yes | — |
experiments[].name | string | Yes | — |
experiments[].playbookId | string (pb_… ID) | Yes | ID (pb_…) |
experiments[].playbookName | string | null | Yes | — |
experiments[].scopeId | string | Yes | — |
experiments[].scopeKind | enum | Yes | One of: "number_assignment", "number_route", "widget_key". |
experiments[].scopeLabel | string | null | Yes | — |
experiments[].startsAt | string (date-time) | null | Yes | — |
experiments[].status | enum | Yes | One of: "draft", "running", "stopped", "completed". |
experiments[].targetMetric | enum | Yes | One of: "target_attainment", "primary_attainment", "reached_rate", "fallback_rate", "opportunity_rate", "attempt_rate", "conversion_after_attempt", "ai_miss_rate", "content_miss_rate", "operations_miss_rate", "caller_miss_rate", "value_per_eligible", "held_rate", "time_to_attempt". |
Errors: 400, 401, 403, 404, 409, 429, 500, with an ErrorBody body.
Example
curl -X GET "$ANSWERSTACK_API_URL/v1/account/experiments" \
-H "Authorization: Bearer $ACCESS_TOKEN"Plan an experiment: two or three published versions of one playbook on a number assignment, a route of a number’s schedule or a widget key, a split, a target metric chosen in advance, a minimum sample and an end date#
POST /v1/account/experiments
Authentication: Bearer token: Authorization: Bearer <token> (Supabase access token).
Request body
application/json, required.
| Field | Type | Required | Description |
|---|---|---|---|
arms | array<object> | Yes | Up to 3 items. |
arms[].playbookVersionId | string (pbv_… ID) | Yes | ID (pbv_…) |
arms[].weight | integer | Yes | Between 10 and 90. |
endsAt | string (date-time) | Yes | — |
groupId | string (grp_… ID) | No | ID (grp_…) |
minSample | integer | No | — |
name | string | Yes | 1–120 characters. |
playbookId | string (pb_… ID) | Yes | ID (pb_…) |
scopeId | string | Yes | 1–64 characters. |
scopeKind | enum | Yes | One of: "number_assignment", "number_route", "widget_key". |
targetMetric | enum | Yes | One of: "target_attainment", "primary_attainment", "reached_rate", "fallback_rate", "opportunity_rate", "attempt_rate", "conversion_after_attempt", "ai_miss_rate", "content_miss_rate", "operations_miss_rate", "caller_miss_rate", "held_rate". |
Response 201
| Field | Type | Required | Description |
|---|---|---|---|
arms | array<object> | Yes | — |
arms[].arm | enum | Yes | One of: "A", "B", "C". |
arms[].playbookVersionId | string (pbv_… ID) | Yes | ID (pbv_…) |
arms[].version | number | null | Yes | — |
arms[].weight | number | Yes | — |
createdAt | string (date-time) | Yes | — |
endReason | enum | null | Yes | One of: "ended", "sample_reached", "manual", "new_version_published", "version_archived", "playbook_archived", "scope_changed". |
endedAt | string (date-time) | null | Yes | — |
endsAt | string (date-time) | Yes | — |
groupId | string (grp_… ID) | Yes | ID (grp_…) |
groupName | string | null | Yes | — |
id | string (exp_… ID) | Yes | ID (exp_…) |
minSample | number | Yes | — |
name | string | Yes | — |
playbookId | string (pb_… ID) | Yes | ID (pb_…) |
playbookName | string | null | Yes | — |
scopeId | string | Yes | — |
scopeKind | enum | Yes | One of: "number_assignment", "number_route", "widget_key". |
scopeLabel | string | null | Yes | — |
startsAt | string (date-time) | null | Yes | — |
status | enum | Yes | One of: "draft", "running", "stopped", "completed". |
targetMetric | enum | Yes | One of: "target_attainment", "primary_attainment", "reached_rate", "fallback_rate", "opportunity_rate", "attempt_rate", "conversion_after_attempt", "ai_miss_rate", "content_miss_rate", "operations_miss_rate", "caller_miss_rate", "value_per_eligible", "held_rate", "time_to_attempt". |
Errors: 400, 401, 403, 404, 409, 429, 500, with an ErrorBody body.
Example
curl -X POST "$ANSWERSTACK_API_URL/v1/account/experiments" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"scopeKind": "number_assignment",
"scopeId": "string",
"playbookId": "pb_2ZPh7XbT0v9Ao4iJ3qK1mN8sRgE",
"arms": [
{
"playbookVersionId": "pbv_2ZPh7XbT0v9Ao4iJ3qK1mN8sRgE",
"weight": 10
}
],
"targetMetric": "target_attainment",
"endsAt": "2026-01-15T15:30:00Z"
}'One experiment and its results per arm: every catalogue metric with n and its interval, and verdicts against the control; the target metric’s is labelled tested once every arm has its sample#
GET /v1/account/experiments/{experimentId}
Authentication: Bearer token: Authorization: Bearer <token> (Supabase access token). Bearer token: Authorization: Bearer <token> (An API token (ans_pat_ or ans_svc_). Only routes that list a scope here accept one, and only with that scope.).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
experimentId | string (exp_… ID) | Yes | ID (exp_…) |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
experiment | Experiment | Yes | — |
experiment.arms | array<object> | Yes | — |
experiment.arms[].arm | enum | Yes | One of: "A", "B", "C". |
experiment.arms[].playbookVersionId | string (pbv_… ID) | Yes | ID (pbv_…) |
experiment.arms[].version | number | null | Yes | — |
experiment.arms[].weight | number | Yes | — |
experiment.createdAt | string (date-time) | Yes | — |
experiment.endReason | enum | null | Yes | One of: "ended", "sample_reached", "manual", "new_version_published", "version_archived", "playbook_archived", "scope_changed". |
experiment.endedAt | string (date-time) | null | Yes | — |
experiment.endsAt | string (date-time) | Yes | — |
experiment.groupId | string (grp_… ID) | Yes | ID (grp_…) |
experiment.groupName | string | null | Yes | — |
experiment.id | string (exp_… ID) | Yes | ID (exp_…) |
experiment.minSample | number | Yes | — |
experiment.name | string | Yes | — |
experiment.playbookId | string (pb_… ID) | Yes | ID (pb_…) |
experiment.playbookName | string | null | Yes | — |
experiment.scopeId | string | Yes | — |
experiment.scopeKind | enum | Yes | One of: "number_assignment", "number_route", "widget_key". |
experiment.scopeLabel | string | null | Yes | — |
experiment.startsAt | string (date-time) | null | Yes | — |
experiment.status | enum | Yes | One of: "draft", "running", "stopped", "completed". |
experiment.targetMetric | enum | Yes | One of: "target_attainment", "primary_attainment", "reached_rate", "fallback_rate", "opportunity_rate", "attempt_rate", "conversion_after_attempt", "ai_miss_rate", "content_miss_rate", "operations_miss_rate", "caller_miss_rate", "value_per_eligible", "held_rate", "time_to_attempt". |
results | ExperimentResults | Yes | — |
results.arms | array<object> | Yes | — |
results.arms[].analysed | number | Yes | — |
results.arms[].arm | enum | Yes | One of: "A", "B", "C". |
results.arms[].assigned | number | Yes | — |
results.arms[].metrics | array<object> | Yes | — |
results.arms[].metrics[].higherIsBetter | boolean | Yes | — |
results.arms[].metrics[].interval | object | null | Yes | — |
results.arms[].metrics[].k | number | Yes | — |
results.arms[].metrics[].label | string | Yes | — |
results.arms[].metrics[].metric | enum | Yes | One of: "target_attainment", "primary_attainment", "reached_rate", "fallback_rate", "opportunity_rate", "attempt_rate", "conversion_after_attempt", "ai_miss_rate", "content_miss_rate", "operations_miss_rate", "caller_miss_rate", "value_per_eligible", "held_rate", "time_to_attempt". |
results.arms[].metrics[].n | number | Yes | — |
results.arms[].metrics[].notEnough | boolean | Yes | — |
results.arms[].metrics[].p | number | null | Yes | — |
results.arms[].metrics[].tested | boolean | Yes | — |
results.arms[].metrics[].unit | enum | Yes | One of: "rate", "mean", "seconds". |
results.arms[].metrics[].unknown | number | Yes | — |
results.arms[].metrics[].value | number | null | Yes | — |
results.arms[].metrics[].verdict | enum | null | Yes | One of: "better", "worse", "no_clear_difference", "not_enough". |
results.arms[].playbookVersionId | string (pbv_… ID) | Yes | ID (pbv_…) |
results.arms[].weight | number | Yes | — |
results.minSample | number | Yes | — |
results.sampleReached | boolean | Yes | — |
results.targetMetric | enum | Yes | One of: "target_attainment", "primary_attainment", "reached_rate", "fallback_rate", "opportunity_rate", "attempt_rate", "conversion_after_attempt", "ai_miss_rate", "content_miss_rate", "operations_miss_rate", "caller_miss_rate", "value_per_eligible", "held_rate", "time_to_attempt". |
Errors: 400, 401, 403, 404, 409, 429, 500, with an ErrorBody body.
Example
curl -X GET "$ANSWERSTACK_API_URL/v1/account/experiments/{experimentId}" \
-H "Authorization: Bearer $ACCESS_TOKEN"Start splitting traffic. Every arm’s effective playbook for the group is computed first; the start is refused if one needs review#
POST /v1/account/experiments/{experimentId}/start
Authentication: Bearer token: Authorization: Bearer <token> (Supabase access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
experimentId | string (exp_… ID) | Yes | ID (exp_…) |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
arms | array<object> | Yes | — |
arms[].arm | enum | Yes | One of: "A", "B", "C". |
arms[].playbookVersionId | string (pbv_… ID) | Yes | ID (pbv_…) |
arms[].version | number | null | Yes | — |
arms[].weight | number | Yes | — |
createdAt | string (date-time) | Yes | — |
endReason | enum | null | Yes | One of: "ended", "sample_reached", "manual", "new_version_published", "version_archived", "playbook_archived", "scope_changed". |
endedAt | string (date-time) | null | Yes | — |
endsAt | string (date-time) | Yes | — |
groupId | string (grp_… ID) | Yes | ID (grp_…) |
groupName | string | null | Yes | — |
id | string (exp_… ID) | Yes | ID (exp_…) |
minSample | number | Yes | — |
name | string | Yes | — |
playbookId | string (pb_… ID) | Yes | ID (pb_…) |
playbookName | string | null | Yes | — |
scopeId | string | Yes | — |
scopeKind | enum | Yes | One of: "number_assignment", "number_route", "widget_key". |
scopeLabel | string | null | Yes | — |
startsAt | string (date-time) | null | Yes | — |
status | enum | Yes | One of: "draft", "running", "stopped", "completed". |
targetMetric | enum | Yes | One of: "target_attainment", "primary_attainment", "reached_rate", "fallback_rate", "opportunity_rate", "attempt_rate", "conversion_after_attempt", "ai_miss_rate", "content_miss_rate", "operations_miss_rate", "caller_miss_rate", "value_per_eligible", "held_rate", "time_to_attempt". |
Errors: 400, 401, 403, 404, 409, 429, 500, with an ErrorBody body.
Example
curl -X POST "$ANSWERSTACK_API_URL/v1/account/experiments/{experimentId}/start" \
-H "Authorization: Bearer $ACCESS_TOKEN"Stop an experiment now. Its traffic goes back to the usual version, and its results so far are kept#
POST /v1/account/experiments/{experimentId}/stop
Authentication: Bearer token: Authorization: Bearer <token> (Supabase access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
experimentId | string (exp_… ID) | Yes | ID (exp_…) |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
arms | array<object> | Yes | — |
arms[].arm | enum | Yes | One of: "A", "B", "C". |
arms[].playbookVersionId | string (pbv_… ID) | Yes | ID (pbv_…) |
arms[].version | number | null | Yes | — |
arms[].weight | number | Yes | — |
createdAt | string (date-time) | Yes | — |
endReason | enum | null | Yes | One of: "ended", "sample_reached", "manual", "new_version_published", "version_archived", "playbook_archived", "scope_changed". |
endedAt | string (date-time) | null | Yes | — |
endsAt | string (date-time) | Yes | — |
groupId | string (grp_… ID) | Yes | ID (grp_…) |
groupName | string | null | Yes | — |
id | string (exp_… ID) | Yes | ID (exp_…) |
minSample | number | Yes | — |
name | string | Yes | — |
playbookId | string (pb_… ID) | Yes | ID (pb_…) |
playbookName | string | null | Yes | — |
scopeId | string | Yes | — |
scopeKind | enum | Yes | One of: "number_assignment", "number_route", "widget_key". |
scopeLabel | string | null | Yes | — |
startsAt | string (date-time) | null | Yes | — |
status | enum | Yes | One of: "draft", "running", "stopped", "completed". |
targetMetric | enum | Yes | One of: "target_attainment", "primary_attainment", "reached_rate", "fallback_rate", "opportunity_rate", "attempt_rate", "conversion_after_attempt", "ai_miss_rate", "content_miss_rate", "operations_miss_rate", "caller_miss_rate", "value_per_eligible", "held_rate", "time_to_attempt". |
Errors: 400, 401, 403, 404, 409, 429, 500, with an ErrorBody body.
Example
curl -X POST "$ANSWERSTACK_API_URL/v1/account/experiments/{experimentId}/stop" \
-H "Authorization: Bearer $ACCESS_TOKEN"