Experiments API

Create, manage, and query experiments. The active experiments endpoint is public. All others require authentication.

List experiments

GET/api/experiments

List all experiments for the current workspace

Returns an array of experiment objects. Optionally filter by status.

ParameterTypeDescription
statusstringFilter by status: draft, running, paused, or completed
curl https://app.apex.inc/api/experiments?status=running \ -H "x-api-key: apex_sk_..."

Create experiment

POST/api/experiments

Create a new experiment in draft status

surface and hypothesis are required. The body is not { name, targetUrl, variants: [{ css }], mode: "ab" }. That shape is rejected.

ParameterTypeDescription
namerequiredstringDisplay name
hypothesisrequiredstringThe testable claim
surfacerequiredstringWhere it runs: web, email, push, in_app, mobile, journey_arm, or paid_channel (an Ad holdout). Reserved surfaces (creative, landing_page, feature_flag) are rejected.
variantsarrayVariant objects. Each variant.surface must match the experiment surface. Omit for paid_channel — Apex creates the two lanes (held back / saw the ads) from holdoutPercent.
paidChannelobjectRequired when surface is paid_channel: { network: meta|google|tiktok|linkedin, adAccountId, adSetIds (1–20), holdoutPercent (0.05–0.5), attachMode: apex|manual, washoutDays? }. Admin-only; the workspace must have Ad holdouts switched on, the network connected, and (Meta) Apex's access to Custom Audiences proven on the setup step. Nothing is counted until GET /api/experiments/{id}/ad-exclusion/verify reads the list as attached on every ad set.
beliefIdstringBelief this experiment tests
curl -X POST https://app.apex.inc/api/experiments \ -H "Content-Type: application/json" \ -H "x-api-key: apex_sk_..." \ -d '{ "name": "Pricing CTA", "hypothesis": "A clearer CTA lifts signup", "surface": "web", "variants": [ { "key": "control", "label": "Control", "surface": "web" }, { "key": "variant_b", "label": "New CTA", "surface": "web" } ] }'

Most shops create website experiments from Experiments → New Experiment (Apex changes the page, or your code does) rather than this POST.

Update experiment

PATCH/api/experiments

Update an existing experiment

ParameterTypeDescription
idrequiredstringExperiment ID
statusstringdraft, running, paused, or completed
namestringUpdated display name
curl -X PATCH https://app.apex.inc/api/experiments \ -H "Content-Type: application/json" \ -H "x-api-key: apex_sk_..." \ -d '{ "id": "exp_abc123", "status": "running" }'

Get active experiments (public)

GET/api/experiments/active

Fetch running experiments for a workspace. Used by the snippet.

ParameterTypeDescription
keyrequiredstringWorkspace key (query parameter)

Info

This endpoint is public. The Apex snippet calls it to apply website experiments on page load.

Experiment object

FieldTypeDescription
idstringUnique experiment identifier
namestringDisplay name
hypothesisstringThe testable claim
surfacestringweb, email, push, in_app, mobile, or journey_arm
statusstringdraft, running, paused, or completed
variantsarrayVariant definitions
beliefIdstringLinked belief, if any