Runs
Base URL: https://api.syntheticusers.io
Every endpoint on this page needs an API key:
Authorization: Bearer sk_live_.... See API keys
for how to create one.
POST /runs
Start a run. The response comes back right away with a run_id; the synthetic
users do their work in the background. Poll the run (below) to watch progress.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
target_url | string (https) | yes | The page to test. Must be HTTPS, and its host must be on your allowlist. Private/internal IPs are rejected. |
persona_ids | string[] | yes | 1–10 personas. Library or custom. Each persona runs as its own session. |
task | string | no | A plain-language goal, e.g. "Sign up for a trial". Leave it out to let the persona explore freely. |
flows | string[] | no | Named steps you want attempted in order. |
credential_ids | string[] | no | Logins to use when the target needs authentication. See Authenticated targets. |
duration_budget | "short" | "medium" | no | How long each session may run. "short" (default) ≈ 15 turns / ~3 min; "medium" ≈ 120 turns / ~20 min. |
guided_exploration | "off" | "standard" | "deep" | no | Default "off". "standard" and "deep" attach a questioner that pushes the persona to probe more before finishing. |
model | string | no | The public API runs on claude-opus-4-8 (Claude Opus 4.8, Anthropic direct), which is also the default. You can omit it. |
Response (202 Accepted)
{ "run_id": "run_01H...", "status": "queued", "sessions": [ { "id": "sess_1", "persona_id": "pers_a" }, { "id": "sess_2", "persona_id": "pers_b" } ], "guided_exploration": "standard"}curl -s -X POST "$API_URL/runs" \ -H "Authorization: Bearer $SYNTHUSERS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "target_url": "https://staging.example.com", "persona_ids": ["pers_..."], "task": "Sign up for a trial", "guided_exploration": "standard" }'GET /runs
List your runs, newest first. Uses cursor pagination.
| Query param | Notes |
|---|---|
limit | 1–100. Default 50. |
status | Filter by queued, running, completed, failed, partial, cancelled. |
cursor | Pass next_cursor from the previous page. |
curl -s "$API_URL/runs?limit=20" \ -H "Authorization: Bearer $SYNTHUSERS_API_KEY"{ "items": [ { "id": "run_01H...", "target_url": "https://staging.example.com", "status": "completed", "guided_exploration": "standard", "created_at": "2026-05-15T18:24:00Z", "session_count": 3 } ], "next_cursor": "1747334640000|run_01H..."}GET /runs/:id
Fetch one run and its sessions. Poll this to track progress.
{ "run_id": "run_01H...", "target_url": "https://staging.example.com", "status": "running", "guided_exploration": "standard", "aggregate_status": "pending", "sessions": [ { "id": "sess_1", "persona_id": "pers_a", "status": "completed" }, { "id": "sess_2", "persona_id": "pers_b", "status": "running" }, { "id": "sess_3", "persona_id": "pers_c", "status": "queued" } ]}A run’s status is one of queued, running, completed, failed,
partial (some sessions failed), or cancelled. Each session’s status is
one of queued, running, completed, or failed.
Reports
Reports are ready once a session’s status is completed. Each format is a
separate endpoint.
Per-session report
GET /runs/:id/sessions/:sid/report.json— structured findings. The shape is stable and carries aschema_version.GET /runs/:id/sessions/:sid/report.md— the same report as Markdown.GET /runs/:id/sessions/:sid/report.html— a rendered HTML report.
Aggregate report (multi-persona)
When a run has more than one persona, an aggregate report compares them.
GET /runs/:id/aggregate-report.jsonGET /runs/:id/aggregate-report.mdGET /runs/:id/aggregate-report.html
The aggregate is ready once its sessions have finished — check
aggregate_status (pending, ready, failed, or not_applicable) on the
run. For a friendlier view, the dashboard renders both reports at
https://app.syntheticusers.io/r/<run_id>.
Other per-session endpoints
GET /runs/:id/sessions/:sid/screenshots/:filename— a PNG captured during the walk. Filenames are zero-padded, e.g.001-landing.png.GET /runs/:id/sessions/:sid/transcript— the full, replay-ready transcript.GET /runs/:id/sessions/:sid/events— a polling feed of session events (sincea millisecond timestamp).GET /runs/:id/sessions/:sid/stream— the same events as a live Server-Sent Events stream.GET /runs/:id/map— a node-and-edge map of the screens the sessions reached (the journey map).
Cancelling a run
POST /runs/:id/cancel asks the platform to stop a run. Cancellation is
best-effort: a session already writing its final report finishes normally. You
can also cancel from the dashboard.