Start an experiment
Starts an A/B test of the agent's live version (the champion) against another saved version of the same agent. Each conversation is assigned to one of the two at its first shopper message, 50/50, and keeps its version for its whole life. The floor of mature conversations per version is computed by the system and the split is fixed, so the body names the candidate and, optionally, a maximum per version. Both versions can no longer change once it starts. Refused with `agent_experiment_already_running` when one runs, and with `agent_experiment_refused` when it cannot start: its `reason` is `agent_not_testable`, `agent_not_answering` (only the agent that answers on its site can be tested), `no_champion`, `invalid_candidate`, `candidate_not_ready` (the candidate could not go live yet), `no_attribution_key` or `no_order_source` (the site cannot measure purchases). Records an audit entry (`agent.experiment_started`) attributed to the API key.
Authorization
ApiKeyAuth A WorkOS org-scoped API key, created from the dashboard's organization settings page. Identifies the tenant every read and write is scoped to. Missing, malformed, unknown, revoked, expired, or non-organization-owned keys all return 401 (no distinction, so the response can't be used to probe which keys or org ids exist).
In: header
Path Parameters
The site id (prefixed site_). A site id that isn't yours is a 404, same as any other cross-tenant id.
The agent id (prefixed agt_).
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
The split (50/50), the floor and the metric are not inputs: a body that names anything else is refused with 400.
Response Body
application/json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
application/problem+json
curl -X POST "https://example.com/api/v1/sites/string/agents/string/experiments" \ -H "Content-Type: application/json" \ -d '{ "candidateVersionId": "agtv_01kvnwmagwf27rc9d7zef4qksf", "maxConversationsPerVersion": 5000 }'{ "data": { "id": "agxp_01kvnwmagvf27rc9cze5rm9e1r", "agentId": "agt_01kvnwmagvf27rc9cze5rm9e1r", "status": "running", "state": "below_floor", "endedReason": null, "startedAt": "2026-10-28T08:00:00.000Z", "endedAt": null, "floorPerVersion": 2400, "maxConversationsPerVersion": null, "detectionLimitPer1000": null, "metric": "conversion_rate", "alpha": 0.1, "championVersionId": "agtv_01kvnwmagvf27rc9cze5rm9e1r", "candidateVersionId": "agtv_01kvnwmagwf27rc9d7zef4qksf", "champion": { "versionId": "agtv_01kvnwmagvf27rc9cze5rm9e1r", "assignedConversations": 0, "matureConversations": 0, "mainDriver": { "id": "conversion_rate", "role": "main", "convertedConversations": 0, "matureConvertedConversations": 0, "rate": null, "matureRate": null }, "secondaryDrivers": [ { "id": "product_shown", "role": "secondary", "unit": "conversations", "value": 0, "currency": null }, { "id": "product_clicked", "role": "secondary", "unit": "conversations", "value": 0, "currency": null }, { "id": "added_to_cart", "role": "secondary", "unit": "conversations", "value": 0, "currency": null }, { "id": "orders", "role": "secondary", "unit": "orders", "value": 0, "currency": null }, { "id": "attributed_revenue", "role": "secondary", "unit": "minor_units", "value": 0, "currency": "EUR" }, { "id": "revenue_per_conversation", "role": "secondary", "unit": "minor_units", "value": null, "currency": "EUR" }, { "id": "average_order_value", "role": "secondary", "unit": "minor_units", "value": null, "currency": "EUR" } ], "mixedCurrencies": false, "band": null, "progress": 0 }, "candidate": { "versionId": "agtv_01kvnwmagwf27rc9d7zef4qksf", "assignedConversations": 0, "matureConversations": 0, "mainDriver": { "id": "conversion_rate", "role": "main", "convertedConversations": 0, "matureConvertedConversations": 0, "rate": null, "matureRate": null }, "secondaryDrivers": [ { "id": "product_shown", "role": "secondary", "unit": "conversations", "value": 0, "currency": null }, { "id": "product_clicked", "role": "secondary", "unit": "conversations", "value": 0, "currency": null }, { "id": "added_to_cart", "role": "secondary", "unit": "conversations", "value": 0, "currency": null }, { "id": "orders", "role": "secondary", "unit": "orders", "value": 0, "currency": null }, { "id": "attributed_revenue", "role": "secondary", "unit": "minor_units", "value": 0, "currency": "EUR" }, { "id": "revenue_per_conversation", "role": "secondary", "unit": "minor_units", "value": null, "currency": "EUR" }, { "id": "average_order_value", "role": "secondary", "unit": "minor_units", "value": null, "currency": "EUR" } ], "mixedCurrencies": false, "band": null, "progress": 0 }, "verdict": { "winner": null, "gapPer1000": null, "confirmableGapPer1000": null } }}List an agent's experiments
Returns a summary of the A/B tests of the agent's versions, newest first, at most 50: the experiment's status, when it started and ended, why it ended, the two versions, the floor and the maximum. It carries no figure and no state: read one experiment with `GET /experiments/{experimentId}` for its figures, its verdict and its daily `series`.
Get an experiment
Returns one experiment with its figures per version, its verdict, its bands and the daily cumulative series of the live chart. The verdict is on the conversion rate only (the main driver); the funnel, orders, revenue and order value are secondary drivers that explain a result and never decide it. Before the floor there is no verdict, and a result that is not conclusive gives the gap the test could confirm (`verdict.confirmableGapPer1000`), never a claim of no difference. Figures are attributed to the assistant (last touch), not incremental. Only conversations with a shopper message count, the starters shown before the first message are the champion's, recent conversations are credited with a delay of up to 24 hours, and tests running at the same time on the site may mix. `404` for an experiment that is not this agent's.