Campaigns & A/B
A campaign is a named bag of links that stores a set of UTM defaults, 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 is stored on the campaign for reporting and for your own tagging.
Automatic inheritance of these fields into the destination URLs of
assigned links is planned, not available yet (see UTM
templates); until then, tag destination URLs
yourself or with the dashboard UTM builder.
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.