Test decisions on a synthetic audience: studies, site audits, copy tests and post simulations.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Bearer followed by your Aetherya API key (aeth_live_...)
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
SECONDARY TOOL. Pose a question to a SINGLE synthetic persona and get one predicted, in-character response — good for an open-ended 'would this confuse someone like this?' sounding-out. The answer is SIMULATED (one persona's predicted reaction), not a real person, and ONE persona is not an audience: it carries no distribution and no disagreement, so never report it as what 'users' or 'the audience' think. For a finding you can act on, use aetherya_test_copy (compare variants) or aetherya_run_study / aetherya_plan_study (a panel with a spread of reactions).
The question to ask the synthetic audience (e.g. 'Would this pricing page confuse you?').
Optional. Background/situation for the audience to consider when answering.
Optional. A persona id or name from aetherya_list_audiences to answer as. If omitted, one of your synthetic audiences is chosen automatically.
Optional. The language to answer in, e.g. 'English' or 'Romanian'. Personas answer in their own native language by default, which is correct for research but unreadable when you asked in another language. Set this to your own language unless you specifically want the persona's.
This tool isn't marked read-only, so it may change something on the server or in an account you connected.
SECONDARY TOOL. Pose a question to a SINGLE synthetic persona and get one predicted, in-character response — good for an open-ended 'would this confuse someone like this?' sounding-out. The answer is SIMULATED (one persona's predicted reaction), not a real person, and ONE persona is not an audience: it carries no distribution and no disagreement, so never report it as what 'users' or 'the audience' think. For a finding you can act on, use aetherya_test_copy (compare variants) or aetherya_run_study / aetherya_plan_study (a panel with a spread of reactions).
| Argument | Type | Description |
|---|---|---|
| context | string | Optional. Background/situation for the audience to consider when answering. |
| audience | string | Optional. A persona id or name from aetherya_list_audiences to answer as. If omitted, one of your synthetic audiences is chosen automatically. |
| language | string | Optional. The language to answer in, e.g. 'English' or 'Romanian'. Personas answer in their own native language by default, which is correct for research but unreadable when you asked in another language. Set this to your own language unless you specifically want the persona's. |
| question* | string | The question to ask the synthetic audience (e.g. 'Would this pricing page confuse you?'). |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"question"
],
"properties": {
"context": {
"type": "string",
"description": "Optional. Background/situation for the audience to consider when answering."
},
"audience": {
"type": "string",
"description": "Optional. A persona id or name from aetherya_list_audiences to answer as. If omitted, one of your synthetic audiences is chosen automatically."
},
"language": {
"type": "string",
"description": "Optional. The language to answer in, e.g. 'English' or 'Romanian'. Personas answer in their own native language by default, which is correct for research but unreadable when you asked in another language. Set this to your own language unless you specifically want the persona's."
},
"question": {
"type": "string",
"minLength": 1,
"description": "The question to ask the synthetic audience (e.g. 'Would this pricing page confuse you?')."
}
},
"additionalProperties": false
}Run a behavioral simulation: a synthetic audience visits a URL and predicts where real users would hesitate, get confused, or drop off, plus messaging-clarity and UX friction findings with concrete fixes. Ideal for evaluating a freshly built or changed page and getting actionable UX/messaging improvements in the same loop. To find out how people experience a flow (sign-up, onboarding, checkout), pass tasks and start_url: the simulated visitors then walk the flow step by step instead of touring the site. By default they stop before the final submit, so nothing is created or bought; pass allow_test_signups only when the user explicitly allows test sign-ups. Payment is never submitted. For pages behind a login, pass credentials for a dedicated test account the user gave you. Results are SIMULATED (predicted behavior of a synthetic audience), not feedback from real users.
| Argument | Type | Description |
|---|---|---|
| url* | string | The full URL of the page to audit (e.g. https://example.com/pricing). |
| focus | string | Optional. What to pay attention to, e.g. 'checkout flow', 'onboarding clarity', 'is the value proposition clear?'. |
| scope | object | Optional. Restrict where visitors may go: 'site' (whole domain, default), 'path' (a subtree, value '/blog') or 'page' (one page, value a path or full URL). |
| tasks | array | Optional flow test (max 5 tasks). Each simulated visitor walks the flow step by step and reports where they stall and how each step felt, instead of touring the site. Use it for 'how do people experience our sign-up / onboarding / checkout' questions, with start_url set to where the flow begins. Runs the ux_journey audit. |
| audience |
Stop a study, instant read, plan, audit or post simulation that is still running. Use it when the user changes their mind or a run was started with the wrong inputs. Finished runs are not affected.
| Argument | Type | Description |
|---|---|---|
| id* | string | run_id for a study or read, autopilotId for a plan, job_id for an audit, or the post simulation id. |
| kind* | string | The kind named in the run tool's response. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"kind",
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "run_id for a study or read, autopilotId for a plan, job_id for an audit, or the post simulation id."
},
"kind": {
"enum": [
"study",
"autopilot",
"audit",
"post_simulation"
],
"type": "string",
"description": "The kind named in the run tool's response."
}
},
"additionalProperties": false
}Compare 2+ image creatives (thumbnails, display banners, social images) against a synthetic audience. Creates the experiment, uploads the images, attaches the audience and drafts the comparison (free). It then returns status 'needs_price_confirmation' with the quoted simulation sessions; nothing is spent until you re-call with accept_sessions >= the quote (pass accept_sessions up front to skip the pause). To confirm a draft already created, pass comparison_id + accept_sessions only. Cost scales with creatives x personas; an audience group is capped at 10 personas per segment. choice_task adds a forced-choice round (choiceCost in the quote). Collect the ranking with aetherya_get_result kind 'creative_comparison'. Results are simulated, not real-user data.
| Argument | Type | Description |
|---|---|---|
| name | string | Name for the comparison. |
| exposure | string | glance = a split-second scroll-past view. |
| platform | string | Where the creatives run. |
| creatives | array | 2-10 creatives to compare. Needed unless you pass comparison_id. |
| choice_task | boolean | Also run a forced-choice task (each persona picks one creative). Adds sessions; the quote shows choiceCost. |
| persona_ids | array | Persona ids (see aetherya_list_audiences), instead of an audience group. |
| comparison_id | string |
Respond to a plan from aetherya_plan_study. Use action 'confirm' with accept_sessions to approve the quoted cost and start the run — this is the point at which simulation sessions are spent, so check with the user first. Use 'answer' to reply to the clarifying questions (answers with the option ids the user picked, or answer for one free-text reply), 'cancel' to abandon the plan, or 'retry' after a failure. After confirming, the run continues and returns its decision brief when it finishes.
| Argument | Type | Description |
|---|---|---|
| action* | string | 'confirm' accepts the quoted cost and starts the run (requires accept_sessions). 'answer' replies to the clarifying questions (requires answers or answer). 'cancel' abandons the plan. 'retry' re-runs a failed plan. |
| answer | string | For 'answer': a free-text reply to the (first) question asked. Prefer answers when the plan lists questions. |
| answers | array | For 'answer': one entry per question from the plan's questions, with the optionId the user picked or their own text. A question left out keeps its default. Only relay what the user said. |
| autopilot_id* | string | The autopilotId from aetherya_plan_study. |
| accept_sessions | number | Required for 'confirm': the exact sessions figure from the plan's estimate. Never invent it — a mismatch is rejected and re-quoted. |
| max_wait_seconds | integer |
Create synthetic-audience personas to simulate against. Describe who you want to model and get back personas (with ids) you can then target as the 'audience' in aetherya_audit_site, aetherya_test_copy, or aetherya_ask_audience. These are SIMULATED personas (engine-generated), not real people. Returns the created personas inline.
| Argument | Type | Description |
|---|---|---|
| count | integer | How many synthetic personas to create (1-25, default 3). |
| market | string | Optional. Target market / locale as a country or region (e.g. 'US', 'DE', 'UK'). |
| category | string | Optional. A category/segment label for the audience (e.g. 'e-commerce', 'fintech'). |
| language | string | Optional. Language for the personas, e.g. 'ro'. |
| segments | array | Optional. Explicit audience segments (max 12); weights follow 'size'. Builds a manual blueprint. |
| pack_name | string | Optional. Name for the saved audience pack. |
| description | string | Who to simulate, in plain language (e.g. 'price-sensitive first-time SaaS buyers in Germany' or 'busy parents shopping for groceries online'). When provided, Aetherya engine-generates personas matching it; omit for a general-consumer audience. |
| website_url |
Create a secret upload link to send a client so they can drop creative files (images, video) for pretesting. Returns the url and expiry; treat the url as a secret and share it only with the client. Needs a workspace admin or manager, and the feature must be enabled for the workspace (otherwise a clear 'not enabled' message).
| Argument | Type | Description |
|---|---|---|
| label* | string | Who or what the link is for, e.g. 'Acme spring banners'. |
| max_files | integer | Max files (default and cap 50). |
| max_total_mb | integer | Max total size in MB (default and cap 2048). |
| expires_in_days | integer | Days until the link expires (1-30, default 14). |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"label"
],
"properties": {
"label": {
"type": "string",
"maxLength": 120,
"minLength": 1,
"description": "Who or what the link is for, e.g. 'Acme spring banners'."
},
"max_files": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "Max files (default and cap 50)."
},
"max_total_mb": {
"type": "integer",
"maximum": 2048,
"minimum": 1,
"description": "Max total size in MB (default and cap 2048)."
},
"expires_in_days": {
"type": "integer",
"maximum": 30,
"minimum": 1,
"description": "Days until the link expires (1-30, default 14)."
}
},
"additionalProperties": false
}Quote how many simulation sessions a run would cost, and roughly what share of your plan it would consume, before committing to it. Free — this never starts a simulation. Use it to size an audience or shorten a study when headroom is tight.
| Argument | Type | Description |
|---|---|---|
| kind* | string | What you are about to run. |
| depth | string | Engagement depth. Cost multiplier: 1x / 2x / 4x. |
| method | string | Required when kind is 'study' — the research method id. |
| variants | integer | Number of copy variants, for a copy test. |
| questions | integer | Number of survey questions. |
| audience_size | integer | Simulated respondents / audience size. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"kind"
],
"properties": {
"kind": {
"enum": [
"study",
"copy_test",
"post",
"survey",
"audit"
],
"type": "string",
"description": "What you are about to run."
},
"depth": {
"enum": [
"single_pass",
"deliberation",
"deep"
],
"type": "string",
"description": "Engagement depth. Cost multiplier: 1x / 2x / 4x."
},
"method": {
"type": "string",
"description": "Required when kind is 'study' — the research method id."
},
"variants": {
"type": "integer",
"description": "Number of copy variants, for a copy test."
},
"questions": {
"type": "integer",
"description": "Number of survey questions."
},
"audience_size": {
"type": "integer",
"description": "Simulated respondents / audience size."
}
},
"additionalProperties": false
}Fetch the result of an audit started by aetherya_audit_site, using its job_id. Returns the full simulated behavioral findings once complete, or a 'running' status to poll again. Results are SIMULATED predicted behavior, not real users.
| Argument | Type | Description |
|---|---|---|
| job_id* | string | The job_id returned by aetherya_audit_site (or an audit report id). |
| include | array | Extra detail to fetch alongside the report. 'journeys' is the step-by-step path each simulated visitor took; 'heatmap' is where attention landed per page. Both are large — ask for them only when the summary is not enough to answer the question. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"job_id"
],
"properties": {
"job_id": {
"type": "string",
"minLength": 1,
"description": "The job_id returned by aetherya_audit_site (or an audit report id)."
},
"include": {
"type": "array",
"items": {
"enum": [
"heatmap",
"journeys"
],
"type": "string"
},
"description": "Extra detail to fetch alongside the report. 'journeys' is the step-by-step path each simulated visitor took; 'heatmap' is where attention landed per page. Both are large — ask for them only when the summary is not enough to answer the question."
}
},
"additionalProperties": false
}Turn a finished study, audit, read or post simulation into a short decision brief: the question, a direct answer, the reasoning with supporting simulated reactions, the risks, and what to do next. This is what you hand a human — use it instead of relaying raw metrics. Reuses the stored brief when one exists, so repeat calls are free (unless language, register or regulated is given: that writes a new brief with a model call). Everything in it comes from SIMULATED behaviour, not real-user research.
| Argument | Type | Description |
|---|---|---|
| id* | string | The run id for a study, or the reportId (not the job_id) for an audit. |
| kind* | string | 'study' for a run_study / test_copy / plan_study / read run id, 'audit' for an audit report id, 'post_simulation' for a simulate_post id. |
| language | string | Optional. Brief language (e.g. 'ro'); sent as reportLanguage. |
| register | string | Optional. Tone register of the brief. |
| regulated | boolean | Optional. Set true for regulated sectors (claims are checked). |
| regenerate | boolean | Re-write a brief that already exists. Costs another model call — leave unset to reuse the stored one. Passing language, register or regulated also writes a new brief. |
Fetch the findings of a run started by aetherya_run_study, aetherya_test_copy, aetherya_audit_site, aetherya_plan_study, aetherya_read, aetherya_simulate_post, aetherya_compare_creatives, aetherya_pretest_video or aetherya_test_flow, using the kind and id from that tool's response. Simulations run longer than a single tool call, so this is the normal way to collect results. All results are SIMULATED predicted behaviour, not real-user data.
| Argument | Type | Description |
|---|---|---|
| id* | string | The id from the run tool — job_id for audits, run_id for studies and copy tests, autopilotId for plans, the simulation id for a post simulation, the comparisonId for a creative comparison, the experimentId for a video analysis, or the flowRunId for a flow test. |
| kind* | string | Which kind of run to fetch. Use the kind named in the run tool's `next` hint. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"kind",
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "The id from the run tool — job_id for audits, run_id for studies and copy tests, autopilotId for plans, the simulation id for a post simulation, the comparisonId for a creative comparison, the experimentId for a video analysis, or the flowRunId for a flow test."
},
"kind": {
"enum": [
"audit",
"study",
"autopilot",
"post_simulation",
"creative_comparison",
"video_analysis",
"flow"
],
"type": "string",
"description": "Which kind of run to fetch. Use the kind named in the run tool's `next` hint."
}
},
"additionalProperties": false
}List the synthetic audiences (simulated personas) in this workspace: their overall shape (where they are, what they do, how much is actually filled in) plus a sample with ids. These are simulated personas, not real people, and a stored persona pool is usually narrower than the audience a decision is about — read the distribution before targeting by id, and prefer describing the audience you want in aetherya_plan_study when the pool does not match it.
No arguments.
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {}
}List the research methods this workspace can run — with the exact stimulus fields each one requires — plus remaining plan headroom and simulation-session balance. Call this before aetherya_run_study or aetherya_test_copy to pick a method and check cost headroom. Everything Aetherya runs is a SIMULATION of a synthetic audience, not real-user research.
| Argument | Type | Description |
|---|---|---|
| section | string | 'methods' lists the research methods available and the inputs each needs. 'limits' returns just your remaining plan headroom and session balance. Default 'all'. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"section": {
"enum": [
"all",
"methods",
"limits"
],
"type": "string",
"description": "'methods' lists the research methods available and the inputs each needs. 'limits' returns just your remaining plan headroom and session balance. Default 'all'."
}
},
"additionalProperties": false
}List the files a client uploaded through an intake link (name, type, size, status, set label, a short-lived download url). The feature must be enabled for the workspace.
| Argument | Type | Description |
|---|---|---|
| link_id* | string | Intake link id from aetherya_create_intake_link. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"link_id"
],
"properties": {
"link_id": {
"type": "string",
"minLength": 1,
"description": "Intake link id from aetherya_create_intake_link."
}
},
"additionalProperties": false
}List the workspace's recent simulations across studies, instant reads, plans, audits and post simulations, newest first, with the kind and id to pass to aetherya_get_result or aetherya_get_brief. Use it to find earlier work instead of re-running it.
| Argument | Type | Description |
|---|---|---|
| kind | string | Only this kind of run. Default 'all'. Studies include copy tests and instant reads. |
| limit | integer | How many to return. Default 15. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"kind": {
"enum": [
"all",
"study",
"autopilot",
"audit",
"post_simulation"
],
"type": "string",
"description": "Only this kind of run. Default 'all'. Studies include copy tests and instant reads."
},
"limit": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "How many to return. Default 15."
}
},
"additionalProperties": false
}Give Aetherya a decision you need to make, in plain English, and it designs the study, picks or builds the audience, prices it, and runs it — then writes a decision brief. Use this when you do not already know which research method fits; use aetherya_run_study when you do. It can also simulate a whole funnel (an ad leading to a landing page, and which call to action people take there): describe the ad, the page URL and the goals in the objective. It always stops for your approval at a price before spending anything: expect status 'needs_price_confirmation' and answer it with aetherya_confirm_study. Call it again with autopilot_id to check on a plan already running. Results are SIMULATED predicted behaviour, not real-user research.
| Argument | Type | Description |
|---|---|---|
| market | string | Optional. Target market, e.g. 'RO'. |
| language | string | Optional. Report language, e.g. 'ro'. |
| register | string | Optional. Report tone register. |
| asset_ids | array | Optional. Ids of ads the user already uploaded to Aetherya (images or videos). Pass them when the objective is about those ads, e.g. a funnel: 'our Instagram ad leads to example.com/offer; do people book a call or use the plan form?'. |
| objective | string | What you need to decide, in plain English — e.g. 'should we price the starter plan at 29 or 49 for early-stage dev teams?'. Starts a new plan. Omit when checking an existing one. |
| audience_id | string | Optional saved audience pack / persona group id (UUID) to draw the sample from. |
Assemble a markdown pretest report (how we worked, one section per set, what the results mean, sealed predictions appendix) from finished simulations. Deterministic unless generateFixes is true (then the model drafts fixes and a one-line summary per set, if enabled on the account); otherwise the recommended fixes are left as placeholders for the analyst. Returns the markdown plus claim-lint warnings to resolve before sending. Seals each set's prediction as a side effect. Results are simulated, not real-user data. For a branded PDF, open the same report in the app at /dashboard/ad-lab/pretest and use Download PDF.
| Argument | Type | Description |
|---|---|---|
| sets* | array | 1-12 finished runs, one report section each. |
| title* | string | Report title. |
| language | string | Report language. Defaults to en. |
| register | string | Writing register. Defaults to neutral. |
| regulated | boolean | True for regulated sectors; claims are linted harder. |
| generateFixes | boolean | Ask the model to draft 3-5 concrete fixes and a one-line summary per set. Default false. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"title",
"sets"
],
"properties": {
"sets": {
"type": "array",
"items": {
"type": "object",
"required": [
"kind",
"id",
"label"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "Comparison, video analysis or research run id."
},
"kind": {
"enum": [
"creative_comparison",
"video_analysis",
"research_run"
],
"type": "string",
"description": "Which kind of finished run this set is."
},
"label": {
"type": "string",
"minLength": 1,
"description": "Section heading for this set."
},
"assumptions": {
"type": "string",
"description": "Assumptions to state in this set's section."
}
},
"additionalProperties": false
},
"maxItems": 12,
"minItems": 1,
"description": "1-12 finished runs, one report section each."
},
"title": {
"type": "string",
"minLength": 1,
"description": "Report title."
},
"language": {
"enum": [
"ro",
"en"
],
"type": "string",
"description": "Report language. Defaults to en."
},
"register": {
"enum": [
"formal",
"neutral"
],
"type": "string",
"description": "Writing register. Defaults to neutral."
},
"regulated": {
"type": "boolean",
"description": "True for regulated sectors; claims are linted harder."
},
"generateFixes": {
"type": "boolean",
"description": "Ask the model to draft 3-5 concrete fixes and a one-line summary per set. Default false."
}
},
"additionalProperties": false
}Pretest a short video (mp4, mov, webm; max 512 MB, 10 minutes) against a synthetic audience: hook score, attention curve, drop-off points. Uploads the file (video_path on this machine, or video_url), splits it into scenes, then returns status 'needs_price_confirmation' with the quote. The quote exists only after preparing, and the draft is free EXCEPT speech-to-text: when you pass no transcript_srt, preparing charges 0.25 to 6 simulation sessions for transcription up front. Analysis cost is personas x 5 + scenes x 0.5 sessions, minimum 10, max 60 personas. Nothing more is spent until you re-call with accept_sessions >= the quote (pass it up front to skip the pause). If preparing is still running the tool returns 'preparing' with experiment_id, video_id and prepare_job_id: call again with those. Collect with aetherya_get_result kind 'video_analysis'. Results are simulated, not real-user data.
| Argument | Type | Description |
|---|---|---|
| name | string | Name for the pretest. |
| segments | array | Limit an audience group to these segment ids. |
| video_id | string | Resume: from an earlier call. |
| placement | string | Where the video runs. |
| video_url | string | http(s) link to a video file. |
| video_path | string | Local mp4/mov/webm file (disabled when AETHERYA_MCP_ALLOW_LOCAL_FILES=0). |
| persona_ids |
Myrias instant read. Reads 2-5 variants against a census-weighted synthetic population for a market, in seconds, and returns each variant's predicted action propensity, its lift over the control, and which demographic archetypes favour it. A variant can be copy (text), a live page (url), an image (image_path, image_url or image_base64) or a video (video_path). Media reads are single-kind: images or videos cannot be mixed with copy, pages or each other. The first read of a new image takes about 30-45 s and may come back running (collect it with aetherya_get_result). A video is uploaded and prepared first, about 1-2 min. Much cheaper and faster than aetherya_test_copy, which is the deeper follow-up. Counts against the monthly read allowance, not simulation sessions. Results are SIMULATED, not real-user data.
| Argument | Type | Description |
|---|---|---|
| title | string | Optional name for the read in your run history. |
| where | string | Where the variants appear. Defaults to 'Landing page'. |
| market | string | Who to read against, as a place: 'United States', 'Germany', 'RO'. Defaults to the US. |
| audience | string | Read against a saved audience (persona group id from aetherya_list_audiences) instead of a market. |
| variants* | array | 2-5 variants to read side by side. Images and videos are read on their own, not mixed with other kinds. |
| target_action | string | The action the variants should drive, e.g. 'Sign up'. |
Attach what actually happened to a sealed prediction (append-only) and get the evaluation. creative_comparison actual: {metric:'ctr', values:[{creativeId?|variant?, value, impressions?, clicks?}]}; impressions and clicks let Aetherya record the result for calibration (see calibrationRecorded). video_analysis actual: {threeSecondHoldPct?, biggestDropSec?, watchedFullPct?}. Other kinds: any object.
| Argument | Type | Description |
|---|---|---|
| id* | string | Sealed prediction id. |
| note | string | Optional free-text note stored with the outcome. |
| actual* | object | The observed outcome. |
| source | string | Where the numbers came from, e.g. 'client_email_2026-10-09'. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"id",
"actual"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "Sealed prediction id."
},
"note": {
"type": "string",
"description": "Optional free-text note stored with the outcome."
},
"actual": {
"type": "object",
"description": "The observed outcome.",
"additionalProperties": {}
},
"source": {
"type": "string",
"description": "Where the numbers came from, e.g. 'client_email_2026-10-09'."
}
},
"additionalProperties": false
}Run a Research Lab study — pricing sensitivity, message testing, concept testing, focus groups — against a synthetic audience and get a structured verdict with segment breakdowns, objections and representative reactions. Call aetherya_list_capabilities first to pick a method and see the inputs it needs. Results are SIMULATED predicted behaviour, not feedback from real users.
| Argument | Type | Description |
|---|---|---|
| depth | string | How deeply each respondent engages. Cost multiplier: single_pass 1x, deliberation 2x, deep 4x. |
| title* | string | Short name for this study, e.g. 'Q3 pricing band for Pro'. |
| market | string | Optional. Target market, e.g. 'RO'. |
| method* | string | Research method id, from aetherya_list_capabilities — e.g. 'messaging_test', 'concept_test', 'feature_adoption', 'pricing_van_westendorp', 'focus_group'. |
| audience | string | Optional saved audience (persona group) id to draw the sample from. Omit to draw from your existing synthetic audience. |
| language | string | Optional. Report language, e.g. 'ro'. |
| register | string | Optional. Report tone register. |
| scenario |
Lock a prediction (a creative comparison ranking, a video analysis, a study or a manual payload) with a SHA-256 hash and timestamp, so it can later be compared with what really happened. Pass source_id to seal a finished simulation, or payload for a manual prediction. Returns the id, hash and sealed payload.
| Argument | Type | Description |
|---|---|---|
| label* | string | Short name, e.g. 'Spring campaign, 3 creatives'. |
| payload | object | Prediction content; required for 'manual'. |
| source_id | string | Id of the comparison, video analysis or study run. |
| source_kind* | string | What is being sealed. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"source_kind",
"label"
],
"properties": {
"label": {
"type": "string",
"minLength": 1,
"description": "Short name, e.g. 'Spring campaign, 3 creatives'."
},
"payload": {
"type": "object",
"description": "Prediction content; required for 'manual'.",
"additionalProperties": {}
},
"source_id": {
"type": "string",
"description": "Id of the comparison, video analysis or study run."
},
"source_kind": {
"enum": [
"creative_comparison",
"video_analysis",
"research_study",
"manual"
],
"type": "string",
"description": "What is being sealed."
}
},
"additionalProperties": false
}Mint a shareable URL for a completed study, audit or creative comparison so someone without an Aetherya account can read the findings. Use it after aetherya_get_brief when the user wants to send the results to a colleague or client, or post them. The link is PUBLIC to anyone who has it. A study shared without options gets its public link plus a preview card for posting; pass expires_in or a password for a private, expiring link instead.
| Argument | Type | Description |
|---|---|---|
| id* | string | The run id for a study, the reportId (not the job_id) for an audit, or the comparison id. |
| kind* | string | 'study' for a research run id, 'audit' for an audit report id, 'creative_comparison' for a compare_creatives comparison id. |
| password | string | Optional password required to open the link. Never returned in the response. |
| expires_in | string | How long the link stays live. Audits and comparisons default to 30d. A study with no expiry and no password gets its public link (stays live until the owner stops sharing it). |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"kind",
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "The run id for a study, the reportId (not the job_id) for an audit, or the comparison id."
},
"kind": {
"enum": [
"study",
"audit",
"creative_comparison"
],
"type": "string",
"description": "'study' for a research run id, 'audit' for an audit report id, 'creative_comparison' for a compare_creatives comparison id."
},
"password": {
"type": "string",
"description": "Optional password required to open the link. Never returned in the response."
},
"expires_in": {
"enum": [
"7d",
"30d",
"90d",
"never"
],
"type": "string",
"description": "How long the link stays live. Audits and comparisons default to 30d. A study with no expiry and no password gets its public link (stays live until the owner stops sharing it)."
}
},
"additionalProperties": false
}Run a post (X, LinkedIn, Instagram, Facebook) or email through a synthetic audience and get predicted engagement, sentiment and representative reactions before publishing. Starts the run and waits briefly; collect with aetherya_get_result kind 'post_simulation'. Results are SIMULATED reactions, not real engagement.
| Argument | Type | Description |
|---|---|---|
| text* | string | The post (or email body) exactly as it would be published. |
| tone | string | Tone of the simulated comments. Default balanced. |
| link_url | string | Link attached to the post, if any. |
| platform* | string | Where the post goes out. |
| image_url | string | Public URL of an image attached to the post, if any. |
| objective | string | What the post is for, e.g. 'drive webinar signups'. |
| persona_ids | array | Specific personas (from aetherya_list_audiences) to use. Omit to use the workspace pool. |
| audience_size | integer | Simulated audience members. Default 100. Drives cost. |
Compare 2-5 copy variants — headlines, value propositions, ad or email copy — against a synthetic audience, and get a ranked verdict with predicted action propensity, comprehension and trust per variant, plus the objections each raises. Results are SIMULATED predicted reactions, not feedback from real users.
| Argument | Type | Description |
|---|---|---|
| where | string | Where this copy appears. |
| audience | string | Optional saved audience (persona group) id to test against. |
| variants* | array | 2-5 copy variants to compare head-to-head. |
| objective | string | What this copy should achieve, e.g. 'get developers to start a free trial'. |
| audience_size | integer | Simulated respondents. Default 30. Drives cost. |
| target_action | string | The action the copy should drive. |
| accept_sessions | number | Only after a 'needs_price_confirmation' result: the exact requiredSessions value from that response, re-sent to authorize the spend. Never guess it. |
| max_wait_seconds | integer | How long to wait inline before handing back an id to poll. Defaults to 45. |
Simulate people who arrive from an ad (image, video or copy), land on a page, and take one of several exits (for example book a consultation, open the plan form, or leave). Reports the exit split per arm. Pass rewrites to compare a changed ad and page copy against the original on the same audience. The first call quotes the cost and starts nothing; call again with accept_cost true once the user agrees. Collect results with aetherya_get_result kind 'flow'. Results are SIMULATED, not real-user data.
| Argument | Type | Description |
|---|---|---|
| ads | array | 0-2 ads. Each simulated visitor sees one ad first; with two, they are split across them. |
| exits* | array | 1-4 ways the visit can end. A visitor takes the first exit whose signal matches, or leaves. Give at least one signal per exit: form_contains (most reliable), url_contains or text_visible. |
| audience | string | Optional. A synthetic audience: a persona id or name from aetherya_list_audiences, or a short free-text description (e.g. 'first-time SaaS buyers'). |
| page_url* | string | The landing page the ads send people to. |
| rewrites | object | Adds a second arm, 'rewrite', run against the same audience as 'original'. Give ads and/or page_copy. |
| num_agents | integer | Simulated visitors per arm. Default 6. Each arm runs this many, and the ads are split round-robin across them. Cost is quoted per arm. |
Recompute the hash of a sealed prediction and report whether it still matches the stored one.
| Argument | Type | Description |
|---|---|---|
| id* | string | Sealed prediction id. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "Sealed prediction id."
}
},
"additionalProperties": false
}| string |
| Optional. A synthetic audience to use: a persona id or name from aetherya_list_audiences, or a short free-text description (e.g. 'first-time SaaS buyers'). If omitted, Aetherya simulates a small mixed audience. |
| objective | string | Optional. What you want to find out, in your own words, e.g. 'how do new users feel about our onboarding flow?'. Sent as written (not paraphrased); steers the simulated visitors and the report. |
| start_url | string | Optional. Where a flow test begins, e.g. https://example.com/signup. Same site as url. Use together with tasks. |
| num_agents | integer | How many simulated visitors walk the page. Default 3. Drives cost — quote it with aetherya_estimate (kind 'audit', audience_size = this number) before raising it. |
| credentials | object | Use a dedicated test account. Sent once, stored encrypted, deleted when the run ends. Never use a real customer or admin account. |
| max_wait_seconds | integer | How long to wait inline before handing back an id to poll. Defaults to 45. |
| allow_test_signups | boolean | Flow tests only. Default false: visitors stop before the final submit, so no account is created and no order is placed. Set true only if the user explicitly allows test sign-ups on this site. Payment is never submitted either way. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"url"
],
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "The full URL of the page to audit (e.g. https://example.com/pricing)."
},
"focus": {
"type": "string",
"description": "Optional. What to pay attention to, e.g. 'checkout flow', 'onboarding clarity', 'is the value proposition clear?'."
},
"scope": {
"type": "object",
"required": [
"mode"
],
"properties": {
"mode": {
"enum": [
"site",
"path",
"page"
],
"type": "string",
"description": "'site', 'path' or 'page'."
},
"value": {
"type": "string",
"description": "For 'path': a subtree like '/blog'. For 'page': a path or full URL."
}
},
"description": "Optional. Restrict where visitors may go: 'site' (whole domain, default), 'path' (a subtree, value '/blog') or 'page' (one page, value a path or full URL).",
"additionalProperties": false
},
"tasks": {
"type": "array",
"items": {
"type": "object",
"required": [
"title"
],
"properties": {
"title": {
"type": "string",
"minLength": 1,
"description": "What the visitor tries to do, e.g. 'Create an account and reach the first screen'."
},
"instructions": {
"type": "string",
"description": "Optional extra guidance for the visitor."
},
"expected_outcome": {
"type": "string",
"description": "Optional. What counts as done, e.g. 'Lands on a welcome or dashboard screen'."
}
},
"additionalProperties": false
},
"maxItems": 5,
"description": "Optional flow test (max 5 tasks). Each simulated visitor walks the flow step by step and reports where they stall and how each step felt, instead of touring the site. Use it for 'how do people experience our sign-up / onboarding / checkout' questions, with start_url set to where the flow begins. Runs the ux_journey audit."
},
"audience": {
"type": "string",
"description": "Optional. A synthetic audience to use: a persona id or name from aetherya_list_audiences, or a short free-text description (e.g. 'first-time SaaS buyers'). If omitted, Aetherya simulates a small mixed audience."
},
"objective": {
"type": "string",
"description": "Optional. What you want to find out, in your own words, e.g. 'how do new users feel about our onboarding flow?'. Sent as written (not paraphrased); steers the simulated visitors and the report."
},
"start_url": {
"type": "string",
"format": "uri",
"description": "Optional. Where a flow test begins, e.g. https://example.com/signup. Same site as url. Use together with tasks."
},
"num_agents": {
"type": "integer",
"maximum": 10,
"minimum": 1,
"description": "How many simulated visitors walk the page. Default 3. Drives cost — quote it with aetherya_estimate (kind 'audit', audience_size = this number) before raising it."
},
"credentials": {
"type": "object",
"required": [
"mode",
"username",
"password"
],
"properties": {
"mode": {
"enum": [
"form",
"basic"
],
"type": "string",
"description": "'form': a login page; 'basic': HTTP basic auth."
},
"password": {
"type": "string",
"maxLength": 512,
"minLength": 1,
"description": "Test account password."
},
"username": {
"type": "string",
"maxLength": 320,
"minLength": 1,
"description": "Test account username or email."
},
"login_url": {
"type": "string",
"format": "uri",
"description": "Form mode: the login page URL, on the audited site."
},
"allowed_hosts": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"maxItems": 5,
"description": "Extra hosts the login may pass through (single sign-on), e.g. ['auth.example.com']."
},
"persona_login": {
"enum": [
"prelogin",
"persona"
],
"type": "string",
"description": "'prelogin' (default): Aetherya logs in once and every visitor starts signed in. 'persona': each visitor logs in itself, which tests the login page too."
}
},
"description": "Use a dedicated test account. Sent once, stored encrypted, deleted when the run ends. Never use a real customer or admin account.",
"additionalProperties": false
},
"max_wait_seconds": {
"type": "integer",
"maximum": 45,
"minimum": 0,
"description": "How long to wait inline before handing back an id to poll. Defaults to 45."
},
"allow_test_signups": {
"type": "boolean",
"description": "Flow tests only. Default false: visitors stop before the final submit, so no account is created and no order is placed. Set true only if the user explicitly allows test sign-ups on this site. Payment is never submitted either way."
}
},
"additionalProperties": false
}| Confirm and run a draft created by an earlier call. |
| accept_sessions | number | Sessions you accept to spend; must cover the quote. |
| audience_group_id | string | Audience group (see aetherya_list_audiences). |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"description": "Name for the comparison."
},
"exposure": {
"enum": [
"glance",
"considered"
],
"type": "string",
"description": "glance = a split-second scroll-past view."
},
"platform": {
"enum": [
"google_display",
"facebook",
"instagram",
"google_search"
],
"type": "string",
"description": "Where the creatives run."
},
"creatives": {
"type": "array",
"items": {
"type": "object",
"required": [
"label"
],
"properties": {
"cta": {
"type": "string",
"description": "Call-to-action text."
},
"body": {
"type": "string",
"description": "Body copy shown with the image."
},
"label": {
"type": "string",
"minLength": 1,
"description": "Short name for the creative."
},
"concept": {
"type": "string",
"description": "Creatives sharing a concept are grouped; the first is its representative."
},
"headline": {
"type": "string",
"description": "Headline shown with the image."
},
"image_url": {
"type": "string",
"description": "http(s) image, png/jpeg/webp, max 8 MB."
},
"image_base64": {
"type": "string",
"description": "data:image/...;base64,... URL, max 8 MB."
}
},
"additionalProperties": false
},
"maxItems": 10,
"minItems": 2,
"description": "2-10 creatives to compare. Needed unless you pass comparison_id."
},
"choice_task": {
"type": "boolean",
"description": "Also run a forced-choice task (each persona picks one creative). Adds sessions; the quote shows choiceCost."
},
"persona_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Persona ids (see aetherya_list_audiences), instead of an audience group."
},
"comparison_id": {
"type": "string",
"description": "Confirm and run a draft created by an earlier call."
},
"accept_sessions": {
"type": "number",
"description": "Sessions you accept to spend; must cover the quote.",
"exclusiveMinimum": 0
},
"audience_group_id": {
"type": "string",
"description": "Audience group (see aetherya_list_audiences)."
}
},
"additionalProperties": false
}| How long to wait inline after confirming before handing back an id. Defaults to 45. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"autopilot_id",
"action"
],
"properties": {
"action": {
"enum": [
"confirm",
"answer",
"cancel",
"retry"
],
"type": "string",
"description": "'confirm' accepts the quoted cost and starts the run (requires accept_sessions). 'answer' replies to the clarifying questions (requires answers or answer). 'cancel' abandons the plan. 'retry' re-runs a failed plan."
},
"answer": {
"type": "string",
"minLength": 1,
"description": "For 'answer': a free-text reply to the (first) question asked. Prefer answers when the plan lists questions."
},
"answers": {
"type": "array",
"items": {
"type": "object",
"required": [
"questionId"
],
"properties": {
"text": {
"type": "string",
"minLength": 1,
"description": "The user's own words, when no option fits."
},
"optionId": {
"type": "string",
"minLength": 1,
"description": "The id of the option the user picked."
},
"questionId": {
"type": "string",
"minLength": 1,
"description": "A question id from the plan's questions."
}
},
"additionalProperties": false
},
"maxItems": 3,
"description": "For 'answer': one entry per question from the plan's questions, with the optionId the user picked or their own text. A question left out keeps its default. Only relay what the user said."
},
"autopilot_id": {
"type": "string",
"minLength": 1,
"description": "The autopilotId from aetherya_plan_study."
},
"accept_sessions": {
"type": "number",
"description": "Required for 'confirm': the exact sessions figure from the plan's estimate. Never invent it — a mismatch is rejected and re-quoted."
},
"max_wait_seconds": {
"type": "integer",
"maximum": 45,
"minimum": 0,
"description": "How long to wait inline after confirming before handing back an id. Defaults to 45."
}
},
"additionalProperties": false
}| string |
| Optional. A site to infer the audience from — Aetherya analyzes it and generates personas that match its likely visitors. |
| brand_context | object | Optional. The brand under test and its competitors, so personas carry brand awareness for that market. Requires segments or website_url; otherwise it is rejected. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"count": {
"type": "integer",
"maximum": 25,
"minimum": 1,
"description": "How many synthetic personas to create (1-25, default 3)."
},
"market": {
"type": "string",
"description": "Optional. Target market / locale as a country or region (e.g. 'US', 'DE', 'UK')."
},
"category": {
"type": "string",
"description": "Optional. A category/segment label for the audience (e.g. 'e-commerce', 'fintech')."
},
"language": {
"type": "string",
"description": "Optional. Language for the personas, e.g. 'ro'."
},
"segments": {
"type": "array",
"items": {
"type": "object",
"required": [
"key",
"label",
"description"
],
"properties": {
"key": {
"type": "string",
"minLength": 1,
"description": "Stable id for the segment, e.g. 'loyal_buyers'."
},
"size": {
"type": "number",
"description": "Relative weight of the segment.",
"exclusiveMinimum": 0
},
"label": {
"type": "string",
"minLength": 1,
"description": "Display name."
},
"description": {
"type": "string",
"minLength": 1,
"description": "Who these people are."
},
"brand_awareness": {
"enum": [
"unaware",
"aware",
"considering",
"customer",
"lapsed"
],
"type": "string",
"description": "How familiar this segment is with the brand."
},
"relationship_to_brand": {
"type": "string",
"description": "Free text, e.g. 'switched to a competitor last year'."
}
},
"additionalProperties": false
},
"maxItems": 12,
"description": "Optional. Explicit audience segments (max 12); weights follow 'size'. Builds a manual blueprint."
},
"pack_name": {
"type": "string",
"description": "Optional. Name for the saved audience pack."
},
"description": {
"type": "string",
"description": "Who to simulate, in plain language (e.g. 'price-sensitive first-time SaaS buyers in Germany' or 'busy parents shopping for groceries online'). When provided, Aetherya engine-generates personas matching it; omit for a general-consumer audience."
},
"website_url": {
"type": "string",
"format": "uri",
"description": "Optional. A site to infer the audience from — Aetherya analyzes it and generates personas that match its likely visitors."
},
"brand_context": {
"type": "object",
"required": [
"brand"
],
"properties": {
"brand": {
"type": "string",
"minLength": 1,
"description": "The brand under test."
},
"market": {
"type": "string",
"description": "Market, e.g. 'Romania'."
},
"competitors": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"maxItems": 8,
"description": "Up to 8 competitor brands."
}
},
"description": "Optional. The brand under test and its competitors, so personas carry brand awareness for that market. Requires segments or website_url; otherwise it is rejected.",
"additionalProperties": false
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"kind",
"id"
],
"properties": {
"id": {
"type": "string",
"minLength": 1,
"description": "The run id for a study, or the reportId (not the job_id) for an audit."
},
"kind": {
"enum": [
"study",
"audit",
"post_simulation"
],
"type": "string",
"description": "'study' for a run_study / test_copy / plan_study / read run id, 'audit' for an audit report id, 'post_simulation' for a simulate_post id."
},
"language": {
"type": "string",
"description": "Optional. Brief language (e.g. 'ro'); sent as reportLanguage."
},
"register": {
"enum": [
"formal",
"neutral"
],
"type": "string",
"description": "Optional. Tone register of the brief."
},
"regulated": {
"type": "boolean",
"description": "Optional. Set true for regulated sectors (claims are checked)."
},
"regenerate": {
"type": "boolean",
"description": "Re-write a brief that already exists. Costs another model call — leave unset to reuse the stored one. Passing language, register or regulated also writes a new brief."
}
},
"additionalProperties": false
}| autopilot_id | string | Check an existing plan instead of starting one. Mutually exclusive with objective. |
| max_wait_seconds | integer | How long to wait inline before handing back an id. Defaults to 45. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"market": {
"type": "string",
"description": "Optional. Target market, e.g. 'RO'."
},
"language": {
"type": "string",
"description": "Optional. Report language, e.g. 'ro'."
},
"register": {
"enum": [
"formal",
"neutral"
],
"type": "string",
"description": "Optional. Report tone register."
},
"asset_ids": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 6,
"description": "Optional. Ids of ads the user already uploaded to Aetherya (images or videos). Pass them when the objective is about those ads, e.g. a funnel: 'our Instagram ad leads to example.com/offer; do people book a call or use the plan form?'."
},
"objective": {
"type": "string",
"minLength": 1,
"description": "What you need to decide, in plain English — e.g. 'should we price the starter plan at 29 or 49 for early-stage dev teams?'. Starts a new plan. Omit when checking an existing one."
},
"audience_id": {
"type": "string",
"description": "Optional saved audience pack / persona group id (UUID) to draw the sample from."
},
"autopilot_id": {
"type": "string",
"minLength": 1,
"description": "Check an existing plan instead of starting one. Mutually exclusive with objective."
},
"max_wait_seconds": {
"type": "integer",
"maximum": 45,
"minimum": 0,
"description": "How long to wait inline before handing back an id. Defaults to 45."
}
},
"additionalProperties": false
}| array |
| Persona ids, instead of an audience group. |
| hook_windows | boolean | Split scenes into hook windows so the opening seconds are scored on their own. Default true. |
| experiment_id | string | Resume: from an earlier call. |
| prepare_job_id | string | Resume: from an earlier call. |
| transcript_srt | string | SRT transcript; skips the speech-to-text charge. |
| accept_sessions | number | Sessions you accept to spend; must cover the quote. |
| audience_group_id | string | Audience group (see aetherya_list_audiences). |
| transcribe_language | string | e.g. ro or en-US. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"description": "Name for the pretest."
},
"segments": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 12,
"description": "Limit an audience group to these segment ids."
},
"video_id": {
"type": "string",
"description": "Resume: from an earlier call."
},
"placement": {
"enum": [
"generic",
"reels",
"shorts",
"tiktok",
"facebook_feed",
"youtube_instream"
],
"type": "string",
"default": "generic",
"description": "Where the video runs."
},
"video_url": {
"type": "string",
"description": "http(s) link to a video file."
},
"video_path": {
"type": "string",
"description": "Local mp4/mov/webm file (disabled when AETHERYA_MCP_ALLOW_LOCAL_FILES=0)."
},
"persona_ids": {
"type": "array",
"items": {
"type": "string"
},
"description": "Persona ids, instead of an audience group."
},
"hook_windows": {
"type": "boolean",
"default": true,
"description": "Split scenes into hook windows so the opening seconds are scored on their own. Default true."
},
"experiment_id": {
"type": "string",
"description": "Resume: from an earlier call."
},
"prepare_job_id": {
"type": "string",
"description": "Resume: from an earlier call."
},
"transcript_srt": {
"type": "string",
"description": "SRT transcript; skips the speech-to-text charge."
},
"accept_sessions": {
"type": "number",
"description": "Sessions you accept to spend; must cover the quote.",
"exclusiveMinimum": 0
},
"audience_group_id": {
"type": "string",
"description": "Audience group (see aetherya_list_audiences)."
},
"transcribe_language": {
"type": "string",
"pattern": "^[a-z]{2}(-[A-Z]{2})?$",
"description": "e.g. ro or en-US."
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"variants"
],
"properties": {
"title": {
"type": "string",
"description": "Optional name for the read in your run history."
},
"where": {
"enum": [
"Homepage hero",
"Landing page",
"Pricing page",
"Paid ad",
"Sales email",
"Social post",
"x",
"instagram",
"facebook",
"youtube",
"tiktok",
"reels",
"shorts"
],
"type": "string",
"description": "Where the variants appear. Defaults to 'Landing page'."
},
"market": {
"type": "string",
"description": "Who to read against, as a place: 'United States', 'Germany', 'RO'. Defaults to the US."
},
"audience": {
"type": "string",
"format": "uuid",
"description": "Read against a saved audience (persona group id from aetherya_list_audiences) instead of a market."
},
"variants": {
"type": "array",
"items": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "A live page to read, http or https."
},
"text": {
"type": "string",
"minLength": 1,
"description": "The copy to read, verbatim."
},
"label": {
"type": "string",
"description": "Optional short name for this variant."
},
"image_url": {
"type": "string",
"format": "uri",
"description": "http(s) image, png/jpeg/webp, max 8 MB."
},
"image_path": {
"type": "string",
"minLength": 1,
"description": "Local png, jpeg or webp file (disabled when AETHERYA_MCP_ALLOW_LOCAL_FILES=0)."
},
"is_control": {
"type": "boolean",
"description": "The current/baseline variant. Exactly one; defaults to the first."
},
"video_path": {
"type": "string",
"minLength": 1,
"description": "Local mp4, mov, m4v or webm file (disabled when AETHERYA_MCP_ALLOW_LOCAL_FILES=0)."
},
"image_base64": {
"type": "string",
"minLength": 1,
"description": "data:image/...;base64,... URL, max 8 MB."
}
},
"additionalProperties": false
},
"maxItems": 5,
"minItems": 2,
"description": "2-5 variants to read side by side. Images and videos are read on their own, not mixed with other kinds."
},
"target_action": {
"type": "string",
"description": "The action the variants should drive, e.g. 'Sign up'."
}
},
"additionalProperties": false
}| string |
| Optional emotional condition from the method's supportedConditions, e.g. 'budget_anxiety'. |
| stimulus* | object | The method's own stimulus fields, keyed by the `key` values in that method's stimulusSchema (see aetherya_list_capabilities). A variant_list field takes an array of { text, isControl } objects, 2-5 entries. |
| objective* | string | The decision this study should inform. |
| regulated | boolean | Optional. True for regulated sectors (claims are checked). |
| hypothesis | string | Optional. What you expect to find. |
| audience_size | integer | Simulated respondents. Defaults to the method's own default (usually 30). Drives cost. |
| accept_sessions | number | Only needed after a 'needs_price_confirmation' result. Pass back the exact requiredSessions value from that response to proceed. |
| max_wait_seconds | integer | How long to wait inline before handing back an id to poll. Defaults to 45. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"method",
"title",
"objective",
"stimulus"
],
"properties": {
"depth": {
"enum": [
"single_pass",
"deliberation",
"deep"
],
"type": "string",
"description": "How deeply each respondent engages. Cost multiplier: single_pass 1x, deliberation 2x, deep 4x."
},
"title": {
"type": "string",
"minLength": 1,
"description": "Short name for this study, e.g. 'Q3 pricing band for Pro'."
},
"market": {
"type": "string",
"description": "Optional. Target market, e.g. 'RO'."
},
"method": {
"type": "string",
"description": "Research method id, from aetherya_list_capabilities — e.g. 'messaging_test', 'concept_test', 'feature_adoption', 'pricing_van_westendorp', 'focus_group'."
},
"audience": {
"type": "string",
"description": "Optional saved audience (persona group) id to draw the sample from. Omit to draw from your existing synthetic audience."
},
"language": {
"type": "string",
"description": "Optional. Report language, e.g. 'ro'."
},
"register": {
"enum": [
"formal",
"neutral"
],
"type": "string",
"description": "Optional. Report tone register."
},
"scenario": {
"type": "string",
"description": "Optional emotional condition from the method's supportedConditions, e.g. 'budget_anxiety'."
},
"stimulus": {
"type": "object",
"description": "The method's own stimulus fields, keyed by the `key` values in that method's stimulusSchema (see aetherya_list_capabilities). A variant_list field takes an array of { text, isControl } objects, 2-5 entries.",
"additionalProperties": {}
},
"objective": {
"type": "string",
"minLength": 1,
"description": "The decision this study should inform."
},
"regulated": {
"type": "boolean",
"description": "Optional. True for regulated sectors (claims are checked)."
},
"hypothesis": {
"type": "string",
"description": "Optional. What you expect to find."
},
"audience_size": {
"type": "integer",
"maximum": 200,
"minimum": 5,
"description": "Simulated respondents. Defaults to the method's own default (usually 30). Drives cost."
},
"accept_sessions": {
"type": "number",
"description": "Only needed after a 'needs_price_confirmation' result. Pass back the exact requiredSessions value from that response to proceed."
},
"max_wait_seconds": {
"type": "integer",
"maximum": 45,
"minimum": 0,
"description": "How long to wait inline before handing back an id to poll. Defaults to 45."
}
},
"additionalProperties": false
}| accept_sessions |
| number |
| Only after a 'needs_price_confirmation' result: the exact requiredSessions value from it, re-sent to authorize the spend. Never guess it. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"platform",
"text"
],
"properties": {
"text": {
"type": "string",
"minLength": 1,
"description": "The post (or email body) exactly as it would be published."
},
"tone": {
"enum": [
"balanced",
"professional",
"casual"
],
"type": "string",
"description": "Tone of the simulated comments. Default balanced."
},
"link_url": {
"type": "string",
"format": "uri",
"description": "Link attached to the post, if any."
},
"platform": {
"enum": [
"x",
"linkedin",
"instagram",
"facebook",
"email"
],
"type": "string",
"description": "Where the post goes out."
},
"image_url": {
"type": "string",
"format": "uri",
"description": "Public URL of an image attached to the post, if any."
},
"objective": {
"type": "string",
"description": "What the post is for, e.g. 'drive webinar signups'."
},
"persona_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"description": "Specific personas (from aetherya_list_audiences) to use. Omit to use the workspace pool."
},
"audience_size": {
"type": "integer",
"maximum": 500,
"minimum": 10,
"description": "Simulated audience members. Default 100. Drives cost."
},
"accept_sessions": {
"type": "number",
"description": "Only after a 'needs_price_confirmation' result: the exact requiredSessions value from it, re-sent to authorize the spend. Never guess it."
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"variants"
],
"properties": {
"where": {
"enum": [
"Homepage hero",
"Landing page",
"Paid ad",
"Sales email",
"Pricing page",
"Social post"
],
"type": "string",
"description": "Where this copy appears."
},
"audience": {
"type": "string",
"description": "Optional saved audience (persona group) id to test against."
},
"variants": {
"type": "array",
"items": {
"type": "object",
"required": [
"text"
],
"properties": {
"text": {
"type": "string",
"minLength": 1,
"description": "One message variant — a headline, value proposition, or short copy block."
},
"label": {
"type": "string",
"description": "Optional short name for this variant."
},
"is_control": {
"type": "boolean",
"description": "Mark the current/baseline copy. Exactly one variant should be the control."
}
},
"additionalProperties": false
},
"maxItems": 5,
"minItems": 2,
"description": "2-5 copy variants to compare head-to-head."
},
"objective": {
"type": "string",
"description": "What this copy should achieve, e.g. 'get developers to start a free trial'."
},
"audience_size": {
"type": "integer",
"maximum": 200,
"minimum": 10,
"description": "Simulated respondents. Default 30. Drives cost."
},
"target_action": {
"enum": [
"Book a demo",
"Sign up",
"Buy",
"Click through",
"Trust the brand",
"Share internally"
],
"type": "string",
"description": "The action the copy should drive."
},
"accept_sessions": {
"type": "number",
"description": "Only after a 'needs_price_confirmation' result: the exact requiredSessions value from that response, re-sent to authorize the spend. Never guess it."
},
"max_wait_seconds": {
"type": "integer",
"maximum": 45,
"minimum": 0,
"description": "How long to wait inline before handing back an id to poll. Defaults to 45."
}
},
"additionalProperties": false
}| accept_cost | boolean | Leave unset on the first call: nothing starts and the quote comes back. Set true only after the user agrees to the quoted cost. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"page_url",
"exits"
],
"properties": {
"ads": {
"type": "array",
"items": {
"type": "object",
"required": [
"label",
"kind"
],
"properties": {
"kind": {
"enum": [
"image",
"video",
"copy"
],
"type": "string",
"description": "What the ad is. asset_id needs image or video."
},
"label": {
"type": "string",
"minLength": 1,
"description": "Short name for the ad, e.g. 'Spring carousel'."
},
"asset_id": {
"type": "string",
"format": "uuid",
"description": "An image or video already uploaded and read through the Read card. The ad is then what that read described (image: its description; video: speech and on-screen text only). Use instead of description."
},
"description": {
"type": "string",
"maxLength": 6000,
"minLength": 1,
"description": "The ad's copy, or what the image or video shows and says. Give this or asset_id."
}
},
"additionalProperties": false
},
"maxItems": 2,
"description": "0-2 ads. Each simulated visitor sees one ad first; with two, they are split across them."
},
"exits": {
"type": "array",
"items": {
"type": "object",
"required": [
"label"
],
"properties": {
"label": {
"type": "string",
"maxLength": 120,
"minLength": 1,
"description": "What this exit is, e.g. 'Book a consultation'."
},
"primary": {
"type": "boolean",
"description": "The exit that matters most. One exit should be primary; the first is used if none is."
},
"text_visible": {
"type": "string",
"description": "Text that appears only after this exit, e.g. a confirmation message."
},
"url_contains": {
"type": "string",
"description": "Part of the thank-you URL, e.g. '/thank-you'."
},
"form_contains": {
"type": "string",
"description": "Words found only in this exit's form or on its final button (not in the other exit's form), e.g. 'Phone' or 'Generate my plan'. The most reliable signal."
}
},
"additionalProperties": false
},
"maxItems": 4,
"minItems": 1,
"description": "1-4 ways the visit can end. A visitor takes the first exit whose signal matches, or leaves. Give at least one signal per exit: form_contains (most reliable), url_contains or text_visible."
},
"audience": {
"type": "string",
"description": "Optional. A synthetic audience: a persona id or name from aetherya_list_audiences, or a short free-text description (e.g. 'first-time SaaS buyers')."
},
"page_url": {
"type": "string",
"format": "uri",
"description": "The landing page the ads send people to."
},
"rewrites": {
"type": "object",
"properties": {
"ads": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"minLength": 1,
"description": "Optional. Defaults to the original ad's label."
},
"asset_id": {
"$ref": "#/properties/ads/items/properties/asset_id",
"description": "An image or video already uploaded and read through the Read card. The ad is then what that read described (image: its description; video: speech and on-screen text only). Use instead of description."
},
"description": {
"type": "string",
"maxLength": 6000,
"minLength": 1,
"description": "The rewritten ad copy or visual description."
}
},
"additionalProperties": false
},
"maxItems": 2,
"description": "Same order and count as ads. Each replaces that ad's description in the rewrite arm."
},
"label": {
"type": "string",
"description": "Name for the rewrite arm. Default 'rewrite'."
},
"page_copy": {
"type": "array",
"items": {
"type": "object",
"required": [
"find",
"replace"
],
"properties": {
"find": {
"type": "string",
"minLength": 1,
"description": "Exact text on the page."
},
"replace": {
"type": "string",
"description": "Text to show instead."
}
},
"additionalProperties": false
},
"maxItems": 40,
"description": "Text swaps applied to the landing page in the rewrite arm only."
}
},
"description": "Adds a second arm, 'rewrite', run against the same audience as 'original'. Give ads and/or page_copy.",
"additionalProperties": false
},
"num_agents": {
"type": "integer",
"maximum": 10,
"minimum": 1,
"description": "Simulated visitors per arm. Default 6. Each arm runs this many, and the ads are split round-robin across them. Cost is quoted per arm."
},
"accept_cost": {
"type": "boolean",
"description": "Leave unset on the first call: nothing starts and the quote comes back. Set true only after the user agrees to the quoted cost."
}
},
"additionalProperties": false
}