Campaigns & A/B
A campaign is a named bag of links that shares a UTM template, an
optional date window, and a single line in your analytics. A/B is
configured per-link via variants[] and is independent of the
campaign system — you can use either, both, or neither.
Create a campaign
curl -X POST \
https://api.elido.app/v1/workspaces/1/campaigns \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Spring 2026 launch",
"description": "Coordinated push across email and paid",
"utm_source": "spring2026",
"utm_medium": "email",
"utm_campaign": "launch",
"start_date": "2026-05-01",
"end_date": "2026-05-31"
}'Names are unique per workspace. The full UTM set (utm_source,
utm_medium, utm_campaign, utm_term, utm_content) is optional
and acts as a template — links assigned to the campaign inherit any
UTM params they don’t override themselves.
Assign links
curl -X POST \
https://api.elido.app/v1/workspaces/1/campaigns/7/links \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "link_ids": [42, 43, 44] }'Up to 100 link IDs per call. A link belongs to at most one campaign;
re-assigning moves it. Setting campaign_id on a link via
PATCH /links/{id} works too if you’d rather keep campaign
assignment in the link payload.
Remove with the same shape against DELETE:
curl -X DELETE \
https://api.elido.app/v1/workspaces/1/campaigns/7/links \
-H "Authorization: Bearer $ELIDO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "link_ids": [42] }'Deleting a campaign nulls campaign_id on its links — they survive.
Endpoints
| Method | Path |
|---|---|
GET | /v1/workspaces/{ws}/campaigns |
POST | /v1/workspaces/{ws}/campaigns |
PATCH | /v1/workspaces/{ws}/campaigns/{id} |
DELETE | /v1/workspaces/{ws}/campaigns/{id} |
GET | /v1/workspaces/{ws}/campaigns/{id}/links |
POST | /v1/workspaces/{ws}/campaigns/{id}/links (assign) |
DELETE | /v1/workspaces/{ws}/campaigns/{id}/links (unassign) |
A/B testing with variants
A link can have any number of variants[]. Each variant has a
destination, a weight, and an optional label. The edge picks one
per request:
{
"destination_url": "https://example.com/control",
"rotation_mode": "weighted",
"variants": [
{ "destination_url": "https://example.com/a", "weight": 50, "label": "A" },
{ "destination_url": "https://example.com/b", "weight": 50, "label": "B" }
]
}rotation_mode controls the strategy:
| Value | Behaviour |
|---|---|
weighted (default) | Per-request random pick proportional to weight |
round_robin | Atomic Redis counter cycles variants[counter % N] |
Round-robin matters when you’re A/B-testing low-volume creatives — weighted random can produce noisy splits at small sample sizes.
Variants are independent of targeting_rules (see Smart
links). When both are set, smart links resolve
first — a matched rule overrides the variant rotation entirely.
In the dashboard
- Campaigns at
/dashboard/campaigns— create, edit, archive, bulk-assign links. - Per-link variants at
/dashboard/links/{id}— add variants inline; weight sliders auto-normalise to 100.