Bloss Docs

Core concepts

Campaigns, cycles, spend, pairs, tags and creator groups — how the Campaign API models your brand.

Developers

The Campaign API describes your brand with a few building blocks: cycles, spend, pairs, tags and creator groups. Read this page before you call the endpoints, so the numbers they return make sense.

Campaigns are sets of cycles

A payout cycle is a date range your brand pays creators for. The API has no separate "campaign" object: a campaign is whatever cycles you pass in cycleIds. Get ids from GET /cycles.

?cycleIds=cyc_sep,cyc_oct   →  "Q3 launch" campaign

Spend = base pay + CPM bonus

Spend is what your brand pays creators: the base pay for each qualifying pair plus the view-based bonus — the same amounts creators see in their payouts. All money is in USD.

GET /campaign/summary can also track a budget: pass the client's prepayment and the response adds metrics.totalRemains (prepayment minus spend), budget.budgetUsedPct, and budget.atThreshold — true once usage reaches thresholdPct (default 70%).

Pairs (sets)

A pair — called a set in the app — is one video a creator posted to up to four platforms (Instagram, TikTok, YouTube, Facebook). Pay lives on the pair, not on the individual posts. GET /campaign/pairs returns one row per pair with its posts nested under videos.

Tags and creator groups

Two filters narrow every campaign endpoint:

FilterScopes toGet ids from
tagIdspairs carrying any of these tagsGET /campaign/tags
groupIdspairs whose creator is in any of these groupsGET /groups
  • Ids within one filter combine as ANY (OR).
  • The two filters combine as AND.
  • Pass __ungrouped__ in groupIds for creators in no group.

Daily spend and filters

GET /campaign/daily returns spend: null for every day when you filter by tag or group — per-day spend can't be split that way. Use GET /campaign/summary (filtered) for a group's total spend, or GET /campaign/tags for spend by tag.

Dates and timezones

Dates you send (from, to) are calendar days, YYYY-MM-DD. Daily figures are bucketed by your brand's timezone (set in SettingsRulesTimezone), so "a day" matches what your team sees in Bloss.

Pagination

GET /campaign/pairs is paginated:

  • limit — rows per page, 1–500 (default 100).
  • cursor — pass the previous response's nextCursor; omit it for the first page. nextCursor is null on the last page.
  • updatedSince — only pairs changed since a timestamp. To keep a copy in sync, store the largest updatedAt you've seen and pass it next time.
sync-pairs.ts
let cursor: string | null = null;
do {
  const url = new URL('https://www.bloss.app/api/v0/campaign/pairs');
  url.searchParams.set('cycleIds', cycleIds.join(','));
  if (cursor) url.searchParams.set('cursor', cursor);

  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.BLOSS_API_KEY}` },
  });
  const page = await res.json();
  await save(page.pairs);
  cursor = page.nextCursor;
} while (cursor);

Was this page helpful?

Last reviewed Oct 12, 2026

Was this page helpful?

Use this page with AI

View as MarkdownAsk ChatGPTAsk Claude

On this page