Skip to main content
Reference material for Social Post Search: filter grammar and operators, nested-array matching, the filterable and sortable field lists, the response field catalog, pagination, field selection, and errors. For worked examples, see Examples.

API summary

Filter grammar

Every filter describes which individual posts to keep. The API checks each post against your filter independently. There are two building blocks:

Single condition

AND / OR group

An empty group is rejected. A conditions array with no entries returns 400 with filter group 'conditions' cannot be empty.

Array fields

hashtags, mentions.person_id, mentions.company_id, mentions.person_url, and mentions.company_url hold several values per post. A condition on one of them is satisfied when any value matches, so hashtags = "hiring" keeps every post that carries that tag among others.

Filter operators

Use the table below to pick the right type for each condition. Every operator works on filterable fields only; see Filterable fields.
Operator footguns.
  • Use => for greater-than-or-equal and =< for less-than-or-equal. They are not >= and <=.
  • in and not_in require JSON arrays. A string value returns 400.
  • is_null and is_not_null require the value key. Omitting it returns 400 with Missing required field: 'filters.value'.
  • geo_distance and geo_exclude work only on actor.location. Any other field, including reactors.location, returns 400.

Geographic radius filters (geo_distance / geo_exclude)

The value is an object describing a center point and a radius: Posts by authors within 25 km of Bengaluru:

Nested-array matching: all_of and has_all

reactors and comments are arrays of nested objects. Each reactor entry has its own reaction_type, title, company, and so on, and each comment has its own text, created_at, and commenter attributes. When you put several conditions on one of these arrays, there are two things you might mean:
  • Same element: one reactor satisfies every condition (a founder whose reaction was PRAISE).
  • Cross element: different reactors each satisfy a condition (a founder reacted and a recruiter reacted, not necessarily the same person).
A plain and group over one nested array means same element. To express cross element, use an all_of group or the has_all operator.

all_of: each condition matched by some element

Each condition inside all_of must be satisfied by at least one array element, evaluated independently. A condition can be a single filter or an and/or group; a group is matched within one element. Posts where some founder reacted and some recruiter reacted:
Returns total_count: 59960. Wrap a condition in an and group to pin it to one element: a founder whose reaction was PRAISE, plus any recruiter.
Returns total_count: 13723. all_of groups nest freely inside and and or groups, so you can combine cross-element requirements with post-level filters such as date_posted.

has_all: every value matched by some element

has_all is shorthand for the common cross-element case: a value list where each value is matched by some element of the array. The same query as the first all_of example:
Returns total_count: 5505. The count is lower than the all_of form because has_all matches each value as a whole term rather than with the typo-tolerant (.) operator.
  • all_of and has_all accept only positive predicates. != or not_in inside them returns 400 with all_of/has_all conditions only support positive predicates; negation operator NOT_EQUALS is not allowed.
  • They work only on the nested arrays reactors and comments. Using them on a flat field returns 400 with all_of/has_all conditions require nested array fields; 'text' is not a nested field.

Filterable fields

Only the fields below can appear in filters. Any other path returns 400 with Unsupported columns in conditions: [...].

Post

Author (actor.*)

Reposter (reposter.*)

Present on repost_quote and repost_without_thoughts rows.

Engagement (engagement.*)

Reactors (reactors.*, nested)

Filter paths are flat even though the response nests the person under reactors[].reactor.

Comments (comments.*, nested)

Filter paths are flat even though the response nests the person under comments[].commenter.

Mentions and attachments

Filter-only fields

These fields accept filters but are not returned and cannot be listed in fields.

Sortable fields

The sort allowlist is narrower than the filter allowlist. Sorting on any other field, including text, returns 400 with Unsupported columns in conditions: ['text'].
  • date_posted (the default, descending)
  • post_type
  • actor.actor_type
  • engagement.total_reactions
  • engagement.total_comments
  • engagement.num_shares
  • engagement.reactions_by_type.LIKE, .PRAISE, .EMPATHY, .INTEREST, .APPRECIATION, .ENTERTAINMENT
  • is_edited
  • has_video
  • poll.closed
  • poll.multi_select
  • document.page_count

Response field reference

Every post carries every group below unless you narrow it with fields. Fields the source record lacks are omitted from actor and reposter rather than returned as null, so treat each actor field as optional.

Post

actor and reposter

actor is the author. reposter is present on reposts and has the same shape.

engagement

reactors[]

Every reaction on the post. The array is returned in full, not just the elements that matched your filter.

comments[]

Every comment on the post, returned in full.

Attachments and metadata

Attachment objects are always present. A post without a document, article, or poll returns the object with empty strings, 0, false, and [] rather than null. Use content_types or the content_type filter to test for an attachment.

Current platform behavior

These are observed behaviors of the current index build, not part of the contract. They resolve at the next full index refresh.
  • has_video is true on every post, and the content_type filter values video and image match every post. Filter on document, article, or poll, and treat has_video and the video and image entries in content_types as unreliable until then.
  • is_not_null overmatches on attachment text fields. Because empty attachments are stored as empty strings, poll.question is_not_null matches every post. Test attachments with content_type instead.

Errors

Every 400, 403, and 500 uses the nested envelope { "error": { "type", "message", "metadata" } }, and none of them charges credits. Branch on error.type rather than string-matching message.
The available_fields list in the unknown-field 400 is cut short here; the API returns every selectable path.

Pagination and sorting

Sorting

sorts is an ordered array. Each item has a field and an order (asc or desc). Sorts apply in array order: the first is the primary key and the second breaks ties. Omitting sorts orders by date_posted descending.
Both keys are required. A sort entry without order returns 400 with Missing required field: 'sorts.0.order'.

Pagination

Pagination is cursor-based. Each response returns a next_cursor, or null at the end of the result set. To fetch the next page, resend the original body with cursor set to the previous next_cursor.
1

Fetch the first page

Omit cursor and set limit to your page size (max 1000).
2

Walk forward

Take next_cursor from the response and pass it back as cursor. Keep filters, sorts, and fields identical. A cursor issued for a different body is rejected with Invalid cursor.
3

Stop when next_cursor is null

A null cursor means you have reached the end of the result set.
total_count is computed once for the query and stays stable across pages.

Dataset freshness

The index is rebuilt periodically from the full post dataset, so every post in a build shares one materialized_at value. The newest posts in the index can be several days old at the time you query. For the latest posts by one person or company, use Enrich Social Posts.

Field selection

Use fields to return only the dot-paths you need. You can request a whole group such as "actor" or "engagement", a sub-object such as "actor.location" or "engagement.reactions_by_type", or a single field such as "actor.name".
  • actor.location is selected whole. Filters accept actor.location.city, but fields does not; request actor.location.
  • Filter-only fields cannot be selected. content_type and materialized_at in fields return 400 with Invalid fields: ....
  • Leave reactors and comments out unless you need them. They are returned in full and a popular post carries thousands of entries.
Recommended default field set: ["share_url", "date_posted", "text", "post_type", "actor.name", "actor.title", "actor.company_name", "actor.crustdata_entity_id", "engagement.total_reactions", "engagement.total_comments"].

What’s next