Endpoint Reference
Base URL: https://api.abtestbot.com
Auth: Authorization: Bearer sk_live_...
All endpoints return the standard {data, meta} wrapper on success and {error: {code, message}} on failure. workspace_id is derived from the API key — you never pass it explicitly.
Sites
`GET /v1/sites`
List all sites registered in your workspace, ordered most-recent first.
Response:
{
"data": [
{
"id": "uuid",
"name": "mystore",
"url": "https://mystore.com",
"platform": "shopify",
"crawl_status": "ok",
"created_at": "2026-04-15T11:40:06.712852+00:00",
"updated_at": "2026-04-15T11:40:06.712852+00:00"
}
],
"meta": { "workspace_id": "uuid" }
}
`POST /v1/sites`
Register a new site. Subject to your plan's site limit (Starter: 1, Pro: 10, Enterprise: 25).
Body:
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | yes | Display name |
url |
string | yes | Fully-qualified URL with scheme |
Response: 201 Created with the full site object (same shape as GET, plus public_key used by the SplitKit tracking snippet).
`GET /v1/sites/:id`
Get one site by ID. Returns 404 not_found if it doesn't exist or belongs to another workspace.
Ideas
`GET /v1/ideas`
List A/B test ideas. Ordered by creation date (newest first).
Query parameters:
| Param | Type | Notes |
|---|---|---|
site_id |
uuid | Filter to one site |
status |
string | new | approved | implemented | rejected | archived |
category |
string | e.g. cta, headline, layout |
limit |
integer | Default 20, max 100 |
offset |
integer | Default 0 |
Response:
{
"data": [
{
"id": "uuid",
"title": "Test CTA button color",
"hypothesis": "Changing from grey to green will increase CTR",
"category": "cta",
"priority": "high",
"status": "new",
"output_type": "html",
"estimated_impact": "high",
"mockup_data": { ... },
"site_id": "uuid",
"sites": { "name": "mystore", "url": "..." },
"created_at": "...",
"updated_at": "..."
}
],
"meta": { "workspace_id": "uuid" }
}
`POST /v1/ideas/generate`
Kick off AI-powered idea generation for a site. Returns 202 Accepted — the work runs asynchronously and emits the ideas.generated webhook when complete (15–30s typical).
Body:
| Field | Type | Required | Notes |
|---|---|---|---|
site_id |
uuid | yes | |
num_ideas |
integer | no | Default 5, max 10 |
output_type |
string | no | html (default) or screenshot |
Response:
{
"data": {
"success": true,
"ideas": [ { "id": "uuid", "title": "...", "hypothesis": "...", ... } ]
},
"meta": { "workspace_id": "uuid" }
}
`GET /v1/ideas/:id`
Get one idea in full, including the parent site summary and mockup data.
`PATCH /v1/ideas/:id`
Update an idea's status — typically after reviewing or implementing it.
Body:
{ "status": "approved" }
Valid status values: new, approved, implemented, rejected, archived.
Experiments
`GET /v1/experiments`
List experiments. Shares the standard pagination contract.
Query parameters:
| Param | Type | Notes |
|---|---|---|
site_id |
uuid | Filter to one site |
status |
string | draft | active | paused | completed | archived |
limit |
integer | Default 20, max 100 |
Response: list of experiments with id, name, status, traffic_split, started_at, ended_at, site_id, plus a nested sites summary.
`POST /v1/experiments`
Create an experiment, optionally from an existing idea.
Body:
| Field | Type | Required | Notes |
|---|---|---|---|
site_id |
uuid | yes | |
name |
string | yes | |
idea_id |
uuid | no | Link the experiment to an existing idea |
variants |
array | no | [{ name: string, traffic_split?: number }] — defaults to 50/50 control + variant |
goals |
array | no | Conversion goals to track |
Response: 201 Created with the full experiment object including generated variants and goals.
`GET /v1/experiments/:id`
Get one experiment with all nested variants, goals, and parent site summary.
`PATCH /v1/experiments/:id`
Transition an experiment's lifecycle.
Body:
{ "action": "pause" }
Valid action values: pause, resume, complete, archive.
Response: { "data": { "id": "...", "status": "paused" } }
Schedules
Recurring idea-generation runs.
`GET /v1/schedules`
List all schedules in your workspace.
`POST /v1/schedules`
Create a schedule.
Body:
| Field | Type | Required | Default |
|---|---|---|---|
site_id |
uuid | yes | — |
enabled |
boolean | no | false |
frequency |
string | no | weekly (also daily, monthly) |
day_of_week |
integer | no | 1 (Monday = 1, Sunday = 7) |
ideas_per_run |
integer | no | 2 |
output_type |
string | no | html |
target_pages |
array | no | [] — specific URLs to target |
`PATCH /v1/schedules/:id`
Update a schedule. Any of the fields above can be partially updated.
Webhooks
Subscribe to events to react to API-driven or UI-driven changes in real time.
`GET /v1/webhooks`
List active webhook endpoints.
Response:
{
"data": [
{
"id": "uuid",
"url": "https://your-app.com/webhooks/abtestbot",
"events": ["ideas.generated", "experiment.launched"],
"is_active": true,
"created_at": "..."
}
]
}
`POST /v1/webhooks`
Register a new webhook endpoint. The 201 response includes a one-time signing secret — store it. Use it to verify incoming webhooks via the X-abTestBot-Signature header (HMAC-SHA256).
Body:
| Field | Type | Required | Notes |
|---|---|---|---|
url |
string | yes | HTTPS endpoint |
events |
array | yes | One or more event types from the list below |
Supported event types:
ideas.generated— a scheduled or manualgeneraterun completedidea.status_changed— an idea moved toapproved/implemented/etc.experiment.launched— an experiment transitioned toactiveexperiment.completed— an experiment concluded (manually or auto)
`DELETE /v1/webhooks/:id`
Deactivate a webhook (soft-delete — flips is_active to false). Returns { "data": { "deleted": true } }.
Versioning
All endpoints live under /v1/. Breaking changes will ship as /v2/ — we don't modify /v1/ contracts once published.