status'draft' | 'running' | 'waiting' | 'ended' required
draft: set up, not started. running: shoppers are being split. waiting: still splitting,
automatic decisions paused. ended: no longer assigning.
decision_metricstring required
completion_rate | email_opt_in | order_conversion | rpv | aov | phone_opt_in | reached_page | product_page_clicked | custom_url_clicked | button_clicked | chose_answer
decision_targetobject nullable
What a targeted metric points at: reached_page {mode: specific | after, page_key}, button_clicked {page_key, component_key}, chose_answer {page_key, component_key, option_id}; null for any other metric
decision_option'manual' | 'when_clear' | 'on_date' | 'ai' required
manual: the merchant decides. when_clear: publish at the first clear result. on_date: decide on
a date. ai: the AI decides.
ai_trigger'when_clear' | 'on_date'
decision_datestring date nullable
The day the test decides, read in timezone, at least seven days out; null when it decides on no date
decides_atstring date-time nullable
decision_date as an instant, midnight at its start in timezone, UTC ISO 8601; null without a date
timezonestring required
IANA name of the timezone decision_date is read in
fallback'keep' | 'revert' | 'notify' required
What happens on the date without a clear result: keep running, put the live version back, or
tell the merchant and wait.
ai_max_runsinteger nullable
How many times the AI may run before it stops; null lets it run as often as the test asks
ai_fallback'when_clear' | 'notify' required
What the test does once the AI has run ai_max_runs times without ending it: decide at the first
clear result without the AI, or tell the merchant and wait.
revenue_tiersstring[] required
The kinds of revenue counted: added_from_quiz | shown_bought_later | bought_not_shown
protect_metricsstring[] required
The metrics the test watches for harm: completion_rate | email_opt_in | order_conversion | rpv | aov | phone_opt_in | reached_page | product_page_clicked | custom_url_clicked | button_clicked | chose_answer
weekly_digestboolean required
Whether a weekly email reports where the test stands
long_run_remindersboolean required
Whether reminder emails go out six weeks after the start and every two weeks after until it ends
merchant_notestring nullable
A note our AI weighs when it decides, up to 2000 characters: context, never an order
periodinteger required
The current counting period: 0 on a draft, 1 once started, one higher each time a new one opens
period_started_atstring date-time nullable
When the current counting period began, UTC ISO 8601; null on a draft
period_reason'started' | 'split_changed' | 'control_published' | 'variant_republished' | 'metric_changed' | 'revenue_tiers_changed' required
Why a counting period began.
clear_since_atstring date-time nullable
When the decision metric first read clear in this counting period, UTC ISO 8601; null until then
srm_flagged_atstring date-time nullable
When the split check found shoppers not landing in the versions as set, UTC ISO 8601; null while healthy
ai_verdict'publish' | 'keep_running' | 'no_change'
What the AI decided last, as the trusted decide path accepted it; a refused verdict lives on the
timeline only.
ai_rationalestring nullable
Our AI's reasoning for its last decision; null before it has decided
winner_arm_idstring nullable
ended_by'manual' | 'auto' | 'ai' | 'fallback_revert'
ended_atstring date-time nullable
outcome'winner_manual' | 'winner_auto' | 'winner_ai' | 'ai_no_change' | 'ai_recommended' | 'ai_keep_running' | 'ai_blocked_credits' | 'srm_flagged' | 'no_winner_notify' | 'reverted' | 'plan_downgraded' | 'ended_manual' | 'cancelled'
How a test ended, in one word.
revisioninteger required
A number that goes up with every change to the test
started_atstring date-time nullable
created_atstring date-time required
updated_atstring date-time required