Conclude an experiment
Ends an experiment for good: the winning arm, or the control without one, becomes the paywall shown at each of its locations, and each feature flag it set goes on giving that arm's value to everyone the flag's own rules and overrides do not name.
Guide: Feature flags and A/B tests
A project secret key: vh_sk_... for production, vh_sk_test_... for test. Keep it on your servers.
In: header
Path parameters
The project's id, proj_.... A secret key works only in the project it belongs to.
The experiment's id, exp_....
Request body
application/json
TypeScript definitions
Use the request body type in TypeScript.
The arm to promote, exp_var_...; omitted, the control arm is promoted.
Examples
curl -X POST "https://api.voidhash.com/api/v1/projects/proj_tz4a98xxat96iws9zmbrgj3a/experiments/exp_c6v8b3n5q0w2e7h7d2k9m4x1/conclude" \ -H "Authorization: Bearer vh_sk_..." \ -H "Content-Type: application/json" \ -d '{ "winningVariantId": "exp_var_n5q0w2e7h7d2k9m4x1c6v8b3" }'{ "id": "exp_c6v8b3n5q0w2e7h7d2k9m4x1", "projectId": "proj_tz4a98xxat96iws9zmbrgj3a", "name": "Onboarding paywall pricing", "description": "The monthly-first paywall against the annual-first one after onboarding.", "hypothesis": "Leading with the annual plan brings more new subscriptions.", "status": "concluded", "primaryMetricEventName": "$subscription.created", "secondaryMetricEventNames": [], "paywallLocationIds": [ "pw_loc_m4x1c6v8b3n5q0w2e7h7d2k9" ], "testedFeatureFlagIds": [], "winningVariantId": "exp_var_n5q0w2e7h7d2k9m4x1c6v8b3", "featureFlagId": "ff_k9m4x1c6v8b3n5q0w2e7h7d2", "isArchived": false, "startedAt": "2026-03-02T09:00:00.000Z", "endedAt": "2026-04-01T09:00:00.000Z", "createdAt": "2026-02-27T15:20:00.000Z", "updatedAt": "2026-04-01T09:00:00.000Z"}{ "error": { "type": "invalid_request", "code": "experiment_variant_not_found", "message": "This experiment has no arm exp_var_q8w2e6r4t0y3u9b7m3x9c5v1.", "param": "winningVariantId" }}{ "error": { "type": "unauthenticated", "code": "invalid_api_key", "message": "This secret key is not valid." }}{ "error": { "type": "permission_denied", "code": "permission_denied", "message": "Insufficient permissions." }}{ "error": { "type": "not_found", "code": "project_not_found", "message": "There is no project proj_tz4a98xxat96iws9zmbrgj3a, or this credential cannot use it.", "param": "projectId" }}{ "error": { "type": "conflict", "code": "experiment_not_started", "message": "Experiment exp_c6v8b3n5q0w2e7h7d2k9m4x1 has not started; there is nothing to conclude." }}{ "error": { "type": "internal", "code": "internal_error", "message": "Something went wrong on our side. Try again, and contact support with the Request-Id header if it keeps failing." }}Response body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
Errors
| Status | type | code | When |
|---|---|---|---|
| 400 | invalid_request | experiment_variant_not_found | When the winner is not one of its arms. |
| 409 | conflict | experiment_not_started | For a draft. |
| 409 | conflict | experiment_concluded | When already concluded. |
It can also fail with the errors every operation shares, such as unauthenticated; see Errors.
More in Experiments
- List experiments
GET - Create an experiment
POST - Retrieve an experiment
GET - Update an experiment
PATCH - Archive an experiment
POST - Unarchive an experiment
POST - Start an experiment
POST - Pause an experiment
POST - List an experiment's arms
GET - Replace an experiment's arms
PUT - Retrieve an experiment's results
GET
Something wrong or missing on this page? Tell us by email or on Discord.