Content selection

A content selection is the answer to “which posts?” Everything downstream — scores, mix bars, analyses, comment samples — is computed over a selection, so getting the selection right is most of the work.

In the dashboard you make a selection by opening a campaign, clicking a tag, or setting the filter bar. The API exposes exactly those levers.

What a selection is

A selection is a set of posts your team owns, resolved at request time, newest first. It is not a saved object; it is a description that the API turns into post ids each time you use it. Two things follow from that:

  • The same description used twice may resolve differently if posts were added, resynced, or archived in between. If you need a frozen set, resolve once and pass the resulting postIds explicitly.
  • A selection never reaches outside your team. Ids you do not own are dropped; a collection you do not own is 404.

The four ways to select

StyleWhere in the dashboardAPI
CollectionOpen a campaign or groupGET /collections/{id}/posts, or selection.collectionId
Content tagsClick a tag facetGET /posts?tag=launch, or selection.posts.tag
Post filtersFilter bar: creator, platform, dates, score, sentimentGET /posts?account=@acme&platform=tiktok…, or selection.posts.*
Explicit idsMulti-select postsGET /posts/{id} per post, or selection.postIds

Collections and tags are both curation — a teammate decided a post belongs. Filters are properties of the post itself. They compose: a collection can be narrowed by tag and filters (selection.collectionId + selection.posts), because “the TikTok posts tagged launch inside the Q4 campaign” is a natural question. Explicit ids stand alone, because they already are the answer.

Collections

Collections are the campaign / group hierarchy in Siftsy. type: campaign rows are top-level; type: group rows are subgroups whose parentId points at a campaign. Selecting a campaign includes every nested group — the same traversal the dashboard uses. Posts carry collectionIds, so you can also join the other way in a warehouse.

GET /analyst/v1/collections
GET /analyst/v1/collections/{collectionId}/posts

Content tags

Tags are free-form labels teammates put on posts (#launch, preorder, ugc). Matching is case-insensitive and the leading # is optional. Several tags match posts carrying any of them.

GET /analyst/v1/posts?tag=launch,preorder

Post filters

Post filters describe the post rather than how it was curated. They all combine with AND, and they evaluate against the values in the post payload you get back, so what you filter on is exactly what you see.

FilterMeaning
accountCreator username or display name (@ optional)
platforminstagram, tiktok, youtube, … (comma list)
linkPost URL, matched loosely (scheme, www., tracking params ignored)
posted_since / posted_untilWhen the post was published
updated_sinceWhen Siftsy last changed its data — the incremental-sync watermark
min_score / max_scoreSiftsy score range
min_*_percent / max_*_percentShare of comments in a sentiment bucket
statusProcessing state; defaults to complete

The full reference is on Filtering posts.

Explicit ids

When you already know the posts — from a previous listing, a spreadsheet, or a frozen snapshot — pass them directly. Up to 1,000 ids per analysis.

One selection, two uses

The same selection appears in two places, and it means the same thing in both:

# List what the selection contains
GET /analyst/v1/posts?account=@acme&tag=launch&platform=tiktok
# Analyze it
POST /analyst/v1/analyses
{ "selection": { "posts": { "account": "@acme", "tag": "launch", "platform": "tiktok" } } }

GET /posts pages through the posts, one page at a time, with meta.filters echoing what was applied. POST /analyses resolves the whole selection at once and echoes it back as selection on the analysis, normalized:

"selection": {
"type": "posts",
"posts": { "account": ["acme"], "tag": ["launch"], "platform": ["tiktok"] },
"status": "complete"
}

type is collection, posts, or postIds — which style you used. Because the echo is normalized, you can store it and replay it later, or diff two analyses to see how their selections differed.

Resolution rules

  • Newest first. Posts are ordered by postedAt descending as they are resolved.
  • Status defaults to complete. That matches dashboard visibility: finished posts, plus posts mid-resync that still have prior data. Use status to opt into pending, archived, and so on.
  • Capped at 1,000 posts. Listings page past that; analyses stop there and set selectionTruncated: true. If you hit the cap, narrow the selection (add a date range or split by collection) rather than trying to analyze everything at once.
  • Empty is an error for analyses. A selection that matches nothing returns 400 from POST /analyses; on GET /posts it is just an empty page.
  • Hidden comments never count. Selection is about posts; comments a teammate hid from analysis are excluded at the next stage automatically.

Choosing a style

  • Reporting on a campaign the team already runs → collection. It tracks what teammates add.
  • Cross-campaign themes (“everything we tagged ugc this quarter”) → tag, optionally with posted_since.
  • Creator or platform roll-ups, incremental warehouse syncs → post filters (account, platform, updated_since).
  • Reproducible analyses, or a set assembled outside Siftsy → explicit ids.

Next: turn a selection into numbers on Analyses.