docs menu
API Reference
Most people work with ImproveFast through their agent using the improve-fast skill — see Quick start. This page documents the plain REST API at https://improve.fast underneath it, for teams building their own integration with curl or any HTTP client.
Important: experimentId handling
POST /api/experiments returns an experimentId that must be passed to every subsequent call. It's a UUID and it's the only credential — anyone with the ID can read and update that experiment, so treat it like a secret.POST /api/experiments
Creates a new experiment with the specified variants. Experiments expire 7 days after creation.
Request Body
variants(array of strings, required): List of variant identifiers to test. Minimum 2 variants required. Must be unique (case-sensitive).
curl
curl -X POST https://improve.fast/api/experiments \
-H "Content-Type: application/json" \
-d '{"variants": ["A", "B", "C"]}'Response
{
"experimentId": "550e8400-e29b-41d4-a716-446655440000",
"variants": ["A", "B", "C"],
"createdAt": "2026-07-17T18:00:00.000Z",
"expiresAt": "2026-07-24T18:00:00.000Z"
}Save this experimentId — you'll need it for all subsequent operations. Treat it like a secret, since it's the only credential for the experiment.
GET /api/experiments/:id
Returns the current status of the experiment: how far along it is, whether it's found a clear winner yet, and the winner's stats once it has.
curl
$ curl https://improve.fast/api/experiments/550e8400-e29b-41d4-a716-446655440000Response (in progress)
{
"experimentId": "550e8400-e29b-41d4-a716-446655440000",
"totalEvaluations": 12,
"progress": 0.06,
"estimatedRemainingEvaluations": 138,
"converged": false,
"variants": [
{ "name": "A", "evaluations": 4, "meanScore": 0.61, "posteriorMean": 0.60, "posteriorStdDev": 0.19 },
{ "name": "B", "evaluations": 5, "meanScore": 0.72, "posteriorMean": 0.70, "posteriorStdDev": 0.17 },
{ "name": "C", "evaluations": 3, "meanScore": 0.58, "posteriorMean": 0.58, "posteriorStdDev": 0.22 }
],
"winner": null
}Response (converged)
{
"experimentId": "550e8400-e29b-41d4-a716-446655440000",
"totalEvaluations": 58,
"progress": 0.16,
"estimatedRemainingEvaluations": 0,
"converged": true,
"variants": [
{ "name": "A", "evaluations": 18, "meanScore": 0.653, "posteriorMean": 0.655, "posteriorStdDev": 0.045 },
{ "name": "B", "evaluations": 22, "meanScore": 0.847, "posteriorMean": 0.848, "posteriorStdDev": 0.038 },
{ "name": "C", "evaluations": 18, "meanScore": 0.712, "posteriorMean": 0.713, "posteriorStdDev": 0.041 }
],
"winner": {
"variantName": "B",
"evaluations": 22,
"meanScore": 0.847,
"stdDev": 0.038,
"confidenceInterval": [0.771, 0.923]
}
}progress just tracks how close the smallest variant is to a 50-evaluation safety limit — it isn't a confidence score. A winner is usually declared well before progress reaches 1.0, as soon as the leading variant has enough evaluations (15 or more), a steady average, and a clear lead over the runner-up. winner is null until then, then becomes an object with the winning variant's stats.
POST /api/experiments/:id/select
Returns the next variant to try. ImproveFast picks it using a technique called Thompson Sampling (a kind of multi-armed bandit algorithm) that leans toward whichever variant is doing best so far, while still trying the others often enough to stay fair. Picks aren't fixed — repeated calls with identical state can return different variants by design.
curl
$ curl -X POST https://improve.fast/api/experiments/550e8400-e29b-41d4-a716-446655440000/selectResponse
{
"variant": "B"
}POST /api/experiments/:id/record
Records the score for one try of a variant. ImproveFast updates its internal stats and checks whether there's a clear winner yet.
Request Body
variant(string, required): The variant identifier being evaluated. Must match one from the experiment'svariants.score(number, required): Normalized outcome score between 0.0 and 1.0 (inclusive). Higher is better. Values outside this range are rejected.
curl
curl -X POST https://improve.fast/api/experiments/550e8400-e29b-41d4-a716-446655440000/record \
-H "Content-Type: application/json" \
-d '{"variant": "B", "score": 0.9}'Response (no winner yet)
{
"experimentId": "550e8400-e29b-41d4-a716-446655440000",
"variant": "B",
"score": 0.9,
"totalEvaluations": 13,
"progress": 0.06,
"estimatedRemainingEvaluations": 137,
"winner": null
}Response (winner declared)
{
"experimentId": "550e8400-e29b-41d4-a716-446655440000",
"variant": "B",
"score": 0.9,
"totalEvaluations": 58,
"progress": 0.16,
"estimatedRemainingEvaluations": 0,
"winner": {
"variantName": "B",
"evaluations": 22,
"meanScore": 0.847,
"stdDev": 0.038,
"confidenceInterval": [0.771, 0.923]
}
}The winner field is null until ImproveFast is confident about a winner, then becomes an object with the winning variant's stats — it's not just the variant name.
Error Handling
All endpoints return errors as JSON with a machine-readable code:
{
"error": {
"code": "VARIANT_NOT_FOUND",
"message": "Variant B not found in experiment 550e8400-e29b-41d4-a716-446655440000"
}
}Error Codes
VALIDATION_ERROR(400) - Request body is malformed, e.g. fewer than 2 variants or a score outside [0, 1]DUPLICATE_VARIANTS(400) - Variant names inPOST /api/experimentsmust be unique (case-sensitive)ALREADY_INITIALIZED(400) - An experiment already exists for the given experimentIdVARIANT_NOT_FOUND(400) - Variant name doesn't match any from the experiment's originalvariantsEXPERIMENT_NOT_FOUND(404) - The experimentId is unknown or the experiment has expired (7-day TTL)NOT_FOUND(404) - The route doesn't existMETHOD_NOT_ALLOWED(405) - Wrong HTTP method for the endpoint