API v3 is live and in beta: expect possible malfunctions and breaking changes in the coming days. If you find a bug, please report it to your Sillage contact.

Query contents

Search the content collected for your key accounts, a page at a time.

Returns the content items of your workspace, most recent first, filtered by the JSON body you send. The list is paged with a cursor: send meta.cursor.next back as cursor until meta.cursor.has_more is false. It returns 25 items per page by default: set limit (up to 100) to get more or fewer. The filters travel in a JSON body, so lists of domains, handles or URLs are not limited by the length of a URL.

Route

POST/api/v3/contents/query

Access modes

Use a workspace API key. The workspace is inferred from the key.

Authorization: Bearer sk_live_...

Body parameters

Every field is optional: an empty body returns the first page of every content item. A field that is not listed is refused with 422.

FieldTypeDescription
cursorstringThe meta.cursor.next of the previous response, to fetch the next page. Omit it for the first page. It only works with the filters it was issued for: reused with other filters, or sent empty, it is refused with 422. See Pagination.
limitintegerNumber of items per page, from 1 to 100. Defaults to 25.
created_at_fromstringOnly contents created at or after this moment. ISO 8601 date and time with a UTC offset, for example 2026-09-01T00:00:00Z. A date without a time is refused with 422. Both bounds are included.
created_at_tostringOnly contents created at or before this moment. ISO 8601 date and time with a UTC offset, for example 2026-09-01T00:00:00Z. A date without a time is refused with 422. Both bounds are included.
content_typesstring[]Only contents of these types: linkedin_comment, recently_promoted, linkedin_reaction, linkedin_post, linkedin_company_post, linkedin_job_posting, web_article, press_release, blog_post.
company_idsinteger[]Only results whose company is one of these companies. Pass company IDs, as returned by Query companies. Between 1 and 100 values.
company_domainsstring[]Only results whose company has one of these website domains, for example acme.com. Between 1 and 100 values.
company_linkedin_handlesstring[]Only results whose company has one of these LinkedIn handles, the last part of the LinkedIn page address. Between 1 and 100 values.
company_linkedin_urlsstring[]Only results whose company has one of these LinkedIn page URLs. Between 1 and 100 values.
lead_idintegerOnly content written by this lead. Use the lead.id shown on each content item, or an ID from the leads endpoints.
response_formatstringnormalized (default) or concise. concise leaves details out. See Response formats.

The four company filters add up: a result matches when its company is any of the company_ids, or has any of the domains, LinkedIn handles or LinkedIn URLs you send. A value that matches no company in your workspace matches nothing, so the answer is an empty list, never an error. The company filters and every other filter all have to match.

Items are sorted from the newest to the oldest. Items created at the same moment keep a stable order, so no item is skipped or repeated from one page to the next.

Example request

curl -X POST "https://api.getsillage.com/api/v3/contents/query" \
  -H "Authorization: Bearer $SILLAGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"limit":10,"content_types":["linkedin_post"],"company_domains":["acme.com","example.com"]}'

Success response

Status: 200 OK

{
  "data": [
    {
      "id": 120384,
      "content_type": "linkedin_post",
      "created_at": "2026-06-12T09:15:00.000Z",
      "details": {
        "linkedin_post_id": "7440055204630249472",
        "is_repost": false,
        "linkedin_url": "https://www.linkedin.com/posts/sillage-signals_activity-7440055204630249472-vKkM",
        "text": "Thank you for featuring us!",
        "posted_at": "2026-06-12T09:00:00.000Z",
        "engagement": {
          "likes": 12,
          "comments": 2,
          "shares": 1
        },
        "author": {
          "type": "person",
          "full_name": "Jean Dupont",
          "first_name": "Jean",
          "last_name": "Dupont",
          "linkedin_url": "https://www.linkedin.com/in/jeandupont",
          "linkedin_headline": "VP Sales @ Acme",
          "position": "VP Sales",
          "avatar_url": "https://example.com/jeandupont.png"
        }
      },
      "lead": {
        "id": 3301,
        "full_name": "Jean Dupont",
        "first_name": "Jean",
        "last_name": "Dupont",
        "linkedin_url": "https://www.linkedin.com/in/jeandupont",
        "linkedin_headline": "VP Sales @ Acme",
        "position": "VP Sales",
        "avatar_url": "https://example.com/jeandupont.png"
      },
      "company": {
        "id": 8421,
        "name": "Acme",
        "domain": "acme.com",
        "linkedin_url": "https://www.linkedin.com/company/acme",
        "linkedin_handle": "acme",
        "logo_url": "https://example.com/acme-logo.png"
      }
    }
  ],
  "meta": {
    "cursor": {
      "next": "eyJjcmVhdGVkQXQiOiIyMDI2LTA2LTEyVDA5OjE1OjAwLjAwMFoiLCJpZCI6MTIwMzg0fQ.k3Jx0w",
      "has_more": true
    },
    "resolved_companies": [
      {
        "company": {
          "id": 8421,
          "name": "Acme",
          "domain": "acme.com",
          "linkedin_url": "https://www.linkedin.com/company/acme",
          "linkedin_handle": "acme",
          "logo_url": "https://example.com/acme-logo.png"
        },
        "matched_by": "company_domains",
        "identifier": "acme.com"
      },
      {
        "company": {
          "id": 9103,
          "name": "Example",
          "domain": "example.com",
          "linkedin_url": "https://www.linkedin.com/company/example",
          "linkedin_handle": "example",
          "logo_url": null
        },
        "matched_by": "company_domains",
        "identifier": "example.com"
      }
    ]
  }
}

When nothing matches, data is an empty array and meta.cursor.has_more is false.

Response fields

FieldTypeDescription
data[].idintegerID of the content item.
data[].content_typestringThe kind of content, one of the values listed in Content types.
data[].created_atstringWhen the content item was created, in ISO 8601.
data[].detailsobjectWhat the content is about. Its shape depends on content_type. Left out with response_format set to concise.
data[].leadobject or nullThe lead who posted, commented or reacted, when they are one of your leads, otherwise null. A summary: id (the ID of the lead, as in Get a lead), full_name, first_name, last_name, linkedin_url, linkedin_headline, position and avatar_url.
data[].companyobject or nullThe company the content is associated with, when it is one of the workspace's companies, otherwise null. A summary: id (its ID in your workspace), name, domain, linkedin_url, linkedin_handle and logo_url.
meta.cursor.nextstring or nullPass it as cursor to fetch the next page. null on the last page.
meta.cursor.has_morebooleantrue when more contents exist after this page, false on the last page.
meta.resolved_companiesarrayThe companies your company filters matched. See meta.resolved_companies.

meta.resolved_companies

Lists the companies your company filters matched, one entry per company and per filter value that matched it. It is an empty array when you send no company filter.

FieldTypeDescription
companyobjectThe matched company, as a summary: id (its ID in your workspace), name, domain, linkedin_url, linkedin_handle and logo_url.
matched_bystringThe filter that matched this company: company_ids, company_domains, company_linkedin_handles or company_linkedin_urls.
identifierstringThe value you sent in that filter, a domain, a handle, a URL, or a company ID as a string.

Response formats

response_format sets what the details field of each item contains:

  • normalized (default): a clean object that depends on the content_type. See the shapes below.
  • concise: details is left out. This is the lightest answer, useful when you only need IDs, types and dates.

Any other value is refused with 422.

Every field inside details is left out when we could not extract it, rather than sent as null, so treat each field as optional, except the keys of an author, which are always present. engagement has the same flat shape for posts and comments: likes, comments (comments on a post, or replies to a comment), shares (posts only), and a count per reaction type (praise, empathy, interest, appreciation) when the source gives it.

LinkedIn posts (linkedin_post, linkedin_company_post)

{
  "linkedin_post_id": "7440055204630249472",
  "linkedin_original_post_id": "7439950617915080704",
  "is_repost": true,
  "linkedin_url": "https://www.linkedin.com/posts/sillage-signals_activity-7440055204630249472-vKkM",
  "text": "Thank you for featuring us!",
  "posted_at": "2026-03-18T15:23:10.325Z",
  "engagement": {
    "likes": 1,
    "comments": 0,
    "shares": 0,
    "praise": 0,
    "empathy": 0
  },
  "author": {
    "type": "company",
    "id": 4012,
    "name": "Sillage",
    "domain": "getsillage.com",
    "linkedin_url": "https://www.linkedin.com/company/sillage-signals/",
    "linkedin_handle": "sillage-signals",
    "logo_url": "https://example.com/sillage-logo.png"
  },
  "mentions": {
    "profiles": [
      {
        "full_name": "Arnaud Weiss",
        "linkedin_url": "https://www.linkedin.com/in/arnaud-weiss-60b6758a"
      }
    ],
    "companies": [
      {
        "name": "Salesforce",
        "linkedin_url": "https://www.linkedin.com/company/salesforce/"
      }
    ]
  },
  "image_urls": [
    "https://media.licdn.com/dms/image/v2/D4E22AQE.../feedshare-shrink_800/0/1710000000000"
  ]
}

linkedin_post_id is the post's own ID on LinkedIn and linkedin_url links to it. image_urls lists the URLs of the images attached to the post. For a repost, is_repost is true and linkedin_original_post_id is the ID of the original post on LinkedIn. author.type is person or company: a person author carries full_name, first_name, last_name, linkedin_url, linkedin_headline, position and avatar_url; a company author carries id (its ID in the workspace, null when it is not one of the workspace's companies), name, domain, linkedin_url, linkedin_handle and logo_url. The keys of an author are always present, null when unknown. Each entry of mentions.profiles has just a full_name and a linkedin_url, and each entry of mentions.companies just a name and a linkedin_url.

LinkedIn comments (linkedin_comment)

{
  "linkedin_comment_id": "7175492449631371265",
  "text": "Congrats on the launch!",
  "linkedin_url": "https://www.linkedin.com/feed/update/urn:li:activity:123?commentUrn=456",
  "posted_at": "2026-03-18T15:05:14.196Z",
  "engagement": {
    "comments": 0,
    "likes": 1,
    "praise": 0,
    "empathy": 0,
    "interest": 0,
    "appreciation": 0
  },
  "author": {
    "type": "person",
    "full_name": "Jean Dupont",
    "first_name": "Jean",
    "last_name": "Dupont",
    "linkedin_url": "https://www.linkedin.com/in/jeandupont",
    "linkedin_headline": "VP Sales @ Acme",
    "position": "VP Sales",
    "avatar_url": "https://example.com/jeandupont.png"
  },
  "post": {
    "content_id": 10762,
    "linkedin_url": "https://www.linkedin.com/feed/update/urn:li:activity:123",
    "text": "We just closed our pre-seed.",
    "author": null
  }
}

linkedin_comment_id is the comment's own ID on LinkedIn and linkedin_url links to it. engagement.comments is the number of replies to the comment. post is the post the comment was left on: content_id is its ID among your contents, to pass to Get a content item to read that post (null when that post is not among your contents), linkedin_url and text are the post's link and text, and author is who published it, typed like the author of a post (null when unknown). A key of post the source does not hold is null.

LinkedIn reactions (linkedin_reaction)

{
  "reaction_type": "praise",
  "author": {
    "type": "person",
    "full_name": "Jean Dupont",
    "first_name": "Jean",
    "last_name": "Dupont",
    "linkedin_url": "https://www.linkedin.com/in/jeandupont",
    "linkedin_headline": "VP Sales @ Acme",
    "position": "VP Sales",
    "avatar_url": "https://example.com/jeandupont.png"
  },
  "post": {
    "content_id": 120384,
    "linkedin_url": "https://www.linkedin.com/posts/sillage-signals_activity-7440055204630249472",
    "text": "We just closed our pre-seed.",
    "author": {
      "type": "company",
      "id": 4012,
      "name": "Sillage",
      "domain": "getsillage.com",
      "linkedin_url": "https://www.linkedin.com/company/sillage-signals/",
      "linkedin_handle": "sillage-signals",
      "logo_url": "https://example.com/sillage-logo.png"
    }
  }
}

reaction_type is like, praise, interest, empathy, entertainment or appreciation. New values may be added; ignore values you don't know. author is the person who reacted and post is the post they reacted to, described like the post of a comment.

LinkedIn job postings (linkedin_job_posting)

{
  "linkedin_job_id": "9988776655",
  "linkedin_url": "https://www.linkedin.com/jobs/view/senior-software-engineer-at-sillage-9988776655",
  "title": "Senior Software Engineer",
  "min_salary": null,
  "max_salary": null,
  "location": "Paris, Île-de-France, France",
  "posted_at": "2025-11-12T00:00:00.000Z",
  "description": "About Us. Sillage helps go-to-market teams turn public signals into pipeline."
}

linkedin_job_id is the job posting's own ID on LinkedIn, location is the job's location as written on the job offer (free text) and description is its full text. min_salary and max_salary are null when no salary range is given for the posting; otherwise each is a number or a text such as "$100K/yr".

Other content types

For recently_promoted, web_article, press_release and blog_post, details is { "text": "..." } when text is available, and left out otherwise.

Errors

StatusMeaning
401The API key is missing or invalid.
422The body is not valid: an unknown field, a value that is not allowed, a date without a time, a limit outside 1 to 100, or a cursor that was not issued to you by this endpoint, was issued for other filters, or is empty. A range that ends before it starts (created_at_from after created_at_to) is refused with the code invalid_date_range; errors.created_at_from says "must be on or before created_at_to".
429Rate limit exceeded.
500An unexpected server error occurred.

Error responses use RFC 9457 problem documents with Content-Type: application/problem+json. type is always about:blank; code tells one problem from another, detail says what went wrong this time, and errors names the field at fault. For example, with limit set to 500:

{
  "type": "about:blank",
  "title": "Unprocessable Entity",
  "status": 422,
  "code": "invalid_body",
  "detail": "Invalid request body",
  "instance": "/api/v3/contents/query",
  "errors": {
    "limit": ["must be at most 100"]
  }
}

On this page