iAdvizeDocs

Filter and paginate conversations

List a site's conversations over the REST API with filters on dates, channel, agent, language, feedback, title keywords, labels and scores, and page through the result with a cursor.

GET /api/v1/sites/{siteId}/conversations returns a site's conversations, newest first, one page at a time. You narrow the list with query parameters and read the next page with a cursor. This page covers both. For the endpoint's schema, see List a site's conversations. To create an API key, see Authentication.

An example

Conversations from September on the Web channel where the need was not met, and where the shopper was frustrated or the assistant deflected a question it could have answered. limit=1 only keeps the response short.

curl -G "https://www.iadvize.ninja/api/v1/sites/YOUR_SITE_ID/conversations" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  --data-urlencode "channel=web" \
  --data-urlencode "from=2026-09-01T00:00:00Z" \
  --data-urlencode "to=2026-10-01T00:00:00Z" \
  --data-urlencode "labels.all=resolution:unresolved" \
  --data-urlencode "labels.any=visitor_frustrated:true|no_unjustified_fallback:fail" \
  --data-urlencode "limit=1"

The response (ids and values are illustrative, and the cursor is shortened):

{
  "data": [
    {
      "id": "conv_01kvnwmagvf27rc9cze5rm9e1r",
      "title": "Waterproof jacket for hiking",
      "channel": "web",
      "language": "en",
      "createdAt": "2026-09-12T08:41:09.123Z",
      "updatedAt": "2026-09-12T08:44:13.123Z",
      "siteId": "site_01kvnwmagvf27rc9cze5rm9e1r",
      "agentId": "agt_01kvnwmagvf27rc9cze5rm9e1r",
      "agentName": "Storefront assistant",
      "agentVersion": 2,
      "agentVersionId": "agtv_01kvnwmagwf27rc9d7zef4qksf",
      "entryWidget": null,
      "pageContext": {
        "pageType": "product",
        "productId": "jacket-123",
        "categoryName": null,
        "pageUrl": "https://shop.example/products/jacket-123"
      },
      "messageCount": 6,
      "durationMs": 184000,
      "feedback": { "positive": 0, "negative": 1 },
      "productEngagement": { "impressions": 3, "clicks": 0 },
      "labelStatus": "labeled",
      "labelSummary": {
        "resolution": "unresolved",
        "reviewReason": "service",
        "scores": { "quality": 0.9, "service": 0.8, "trust": 1 },
        "failedCriteria": ["no_unjustified_fallback"]
      }
    }
  ],
  "meta": {
    "nextCursor": "eyJhdCI6IjIwMjYt…"
  }
}

To read the next page, send the same request with cursor set to meta.nextCursor. Keep every filter as it was. nextCursor is null on the last page.

curl -G "https://www.iadvize.ninja/api/v1/sites/YOUR_SITE_ID/conversations" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  --data-urlencode "channel=web" \
  --data-urlencode "from=2026-09-01T00:00:00Z" \
  --data-urlencode "to=2026-10-01T00:00:00Z" \
  --data-urlencode "labels.all=resolution:unresolved" \
  --data-urlencode "labels.any=visitor_frustrated:true|no_unjustified_fallback:fail" \
  --data-urlencode "limit=1" \
  --data-urlencode "cursor=eyJhdCI6IjIwMjYt…"

Filters

Every filter is optional. Filters combine with AND. A parameter that is not in this table, or a single-valued parameter sent twice, is a 400 with the code invalid_request.

ParameterMatches
from, toThe conversation's creation time. ISO 8601 with an offset, for example 2026-09-01T00:00:00Z. from is inclusive, to is exclusive.
channelweb, hosted or playground.
agentIdConversations that ran through this agent, whatever its version. An agt_ id.
languageThe panel language recorded on the conversation: fr, en, de, it, es or nl.
feedbackpositive or negative: at least one message of the conversation has a rating of that kind.
keywordsA word or phrase in the conversation title, case-insensitive. Repeat the parameter to require several terms: all of them must appear. Up to 20, 200 characters each.
labels.allThe conversation's labels include every token listed. Repeat the parameter for several tokens.
labels.anyEach occurrence is one group of tokens separated by |. The conversation must match at least one token in every group. Repeat for several groups.
labels.noneThe conversation's labels include none of the tokens listed. Tokens ending in :true only. Needs labels.all, labels.any, from or to alongside it.
quality.min, quality.maxThe quality score of the conversation's label record, from 0 to 1, bounds included. Same for service.* and trust.*.
labelStatuslabeled, pending, failed or not_eligible. See the four statuses.

A label token is <label>:<value>, for example resolution:unresolved, visitor_frustrated:true or grounded:fail. GET /api/v1/labels/vocabulary lists every token the filters accept. See Read labels over the API.

A few rules to know:

  • Labels, scores and labelStatus. A labels.* or score filter only matches labeled conversations. Combining one with a labelStatus other than labeled is an invalid_filter, and so is a token the vocabulary doesn't contain.
  • not_applicable has no token. A criterion can be filtered on pass or fail. A conversation where the criterion was not_applicable matches neither.
  • A score bound skips unscored conversations. A conversation with no value for that score never matches a bound on it.
  • Labeling coverage. Conversations of all three channels (web, hosted and playground) are labeled. A label arrives 30 to 90 minutes after a conversation goes quiet, so a recent conversation reads pending. A conversation whose last activity is more than 30 days old is not labeled. An empty result for a label filter is therefore not proof that a conversation doesn't exist.
  • Labels are read as of the published taxonomy. The filters and the labelSummary come from the current label of each conversation, under taxonomy v1.1.

Pages and cursors

  • Order. Newest first, by creation time. A conversation resumed later keeps its place.
  • Page size. limit is an integer from 1 to 100, and defaults to 25. Anything else is a 400.
  • The cursor is opaque. Don't parse it or build one. Pass meta.nextCursor back as cursor exactly as you received it.
  • A cursor belongs to its filters. Send a cursor with different filters and you get cursor_mismatch. To change the filters, start again without a cursor. The order in which you repeat a parameter (labels.all, keywords) doesn't matter. limit and count aren't part of the listing, so you can change them between pages.
  • A cursor the API didn't issue gets invalid_cursor.
  • An empty cursor= is the same as no cursor.

Both errors are described on Errors and rate limits.

Count

Add count=true to get a total in meta.count:

{ "meta": { "nextCursor": null, "count": { "value": 120, "capped": false } } }

The count is capped at 10,000. When the real total is larger, value is 10,000 and capped is true. The count ignores cursor and limit: it is the total for the filters on the request. meta.count is absent when you don't ask for it. The figures in this snippet are made up.

What each conversation carries

Every item, and the conversation returned by Get a conversation, has:

FieldContent
messageCountNumber of messages.
durationMsLast activity minus creation time, in milliseconds.
feedbackpositive and negative: how many messages carry each rating.
productEngagementimpressions and clicks on the product cards the conversation rendered.
entryWidgetThe engagement widget it was opened from, or null.
pageContextThe page the conversation started from, as your tag declared it, or null. See The page URL.
labelStatuslabeled, pending, failed or not_eligible.
labelSummaryFor a labeled conversation: resolution, reviewReason, scores and failedCriteria (the criteria the judge failed). null for the other three statuses.

The single conversation adds two fields: messages, the ordered transcript, and metadata, the test context of a Playground conversation (null otherwise). The list never returns messages. No field identifies the shopper.

The page URL

pageContext.pageUrl is the page's address without its query string, its fragment and its ; path parameters. Only the origin and the path are kept, so https://shop.example/products/jacket-123?utm_source=mail#reviews is returned as https://shop.example/products/jacket-123. An address with another scheme, such as javascript: or mailto:, is returned as null.

The path itself is left as your tag sent it, and it can still contain identifiers you put in your own URLs, such as an order number or a customer slug. Treat pageUrl as customer data: store and share it with the same care as the rest of your own data.

To read the full label record of one conversation, use GET /api/v1/sites/{siteId}/conversations/{id}/labels. It is described in Conversation labeling.

On this page