Create a campaign
Check a public post, create a campaign and its challenge from the post URL, then end or delete it.
A campaign carries one challenge: the public Instagram or TikTok post creators engage with. You create both in a single call; the response's challenge.id is the challengeId every later request takes. Concepts explains how they relate.
Campaigns are part of engagement verification, which is available on request. To read a post's comments or metrics without one, use the data lookups.
Check the post
Confirms a URL points at a post the API can read, and returns its cover image, before anything is created. Nothing is stored.
curl -G {API_BASE_URL}/admin/posts/thumbnail \
-H "Authorization: Bearer <API_TOKEN>" \
--data-urlencode "url=https://www.instagram.com/p/ABC123/?igsh=xyz"{
"data": {
"platform": "instagram",
"contentType": "post",
"contentId": "ABC123",
"canonicalUrl": "https://www.instagram.com/p/ABC123/",
"thumbnailUrl": "https://..."
}
}Send canonicalUrl as the challenge's targetUrl. Most posts answer in about a second; a few take up to 40 seconds, so set a generous client timeout. A 404 or 422 means the post cannot be read and the campaign's lookups would fail too; see Data lookup errors.
Create
/admin/campaignscurl -X POST {API_BASE_URL}/admin/campaigns \
-H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"brandId": 1,
"title": "Summer Challenge 2026",
"description": "Comment on our Instagram post",
"pointsReward": 100,
"challenge": {
"targetUrl": "https://www.instagram.com/p/ABC123/",
"instructionText": "Leave a comment with #SummerVibes",
"action": "comment"
}
}'| Field | Required | Notes |
|---|---|---|
brandId | yes | Brand that owns the campaign and receives its webhooks |
title | yes | |
pointsReward | yes | Whole number, 1 or more. Points issued on reward.issued. Only used by engagement verification, but required whether or not you use it |
challenge.targetUrl | yes | Public post URL. The platform, content type, and content id are parsed from it |
challenge.action | no | comment (default, Instagram and TikTok) or like (Instagram only) |
challenge.instructionText | no | Shown to creators by your UI |
description, imageUrl, startsAt, endsAt | no |
Response 201:
{
"data": {
"campaign": {
"id": 1,
"brandId": 1,
"title": "Summer Challenge 2026",
"pointsReward": 100,
"isActive": true,
"startsAt": null,
"endsAt": null,
"createdAt": "2026-06-01T09:00:00.000Z"
},
"challenge": {
"id": 1,
"campaignId": 1,
"platform": "instagram",
"contentType": "post",
"contentId": "ABC123",
"canonicalUrl": "https://www.instagram.com/p/ABC123/",
"instructionText": "Leave a comment with #SummerVibes"
}
}
}Store data.challenge.id. The challenge's stored comments and metrics, likers and attempts are all addressed by challengeId; none of those routes take a URL or shortcode.
Set challenge.action to "like" only for Instagram posts. Liker fetching is not available for TikTok, so a like challenge on a TikTok URL cannot be verified.
Read
GET /campaigns lists campaigns; GET /campaigns/{id} returns one with its challenge.
The list is not the create response reshaped. Each row flattens the campaign, adds brandName and brandLogoUrl, nests a trimmed challenge (id, platform, contentType, canonicalUrl, instructionText), and adds myAttempt — the calling token's own attempt on that challenge, or null. It carries no isActive, because only active campaigns are listed; use GET /campaigns/{id} for one that has ended.
End
/admin/campaigns/{id}/endSets isActive to false and endsAt to now (an earlier endsAt is kept). Attempts and rewards are preserved. Calling it again is a no-op.
{ "data": { "id": 1, "isActive": false, "endsAt": "2026-07-01T00:00:00.000Z" } }Delete
/admin/campaigns/{id}Hard-deletes the campaign, its challenge, and every stored comment and metrics snapshot. Allowed only while the challenge has zero attempts; otherwise the call returns 409 and you should end the campaign instead.
| Status | Meaning |
|---|---|
200 | Deleted. Body: { "data": { "id": 1 } } |
404 | Campaign not found |
409 CAMPAIGN_HAS_ACTIVITY | Campaign has attempts. Use end |
Last updated on