Pagination

Most list endpoints in the Virlo API are paginated, and you always drive them with the same two knobs: limit (how many items per page) and either page (1-indexed) or offset (starting position). What differs is the shape of the response — the API has grown three pagination shapes, plus a set of endpoints that return a complete result with no pagination at all. Knowing which one an endpoint uses saves you a surprise. This guide documents all four cases.

Parameters

The same parameters apply everywhere:

  • Name
    limit
    Type
    integer
    Description

    Number of items per page. Between 1 and 100 on most endpoints. Default is 50; some list endpoints use smaller defaults (Satellite runs 25; tracking lists, sounds discovery, and agent sounds 20). Values above 100 are clamped to 100, not rejected; limit=0 or negative returns 400. Tracking exceptions: creator posts accepts up to 200 and creator snapshots up to 365 — those two reject over-max values with 400 instead of clamping.

  • Name
    page
    Type
    integer
    Description

    The page number to fetch. 1-indexed. Default is 1. The API converts page to offset internally where needed.

  • Name
    offset
    Type
    integer
    Description

    The starting position, as an alternative to page. Some sub-resource endpoints (videos, slideshows, ads, outliers, runs) surface offset directly in the response.

Which shape does an endpoint use?

ShapeWhere the list livesMetadataEndpoints
A — nested + offsetInside data, under a resource-named key (videos, slideshows, ads, outliers)total, limit, offset (creators/outliers also add has_more)Agent / Orbit / Comet videos, slideshows, ads, and creator-outlier lists; Satellite runs list
B — envelope + pagination objectdata is the array itselfpagination object (page, limit, total, total_pages, has_next_page, has_prev_page)Agent / Orbit / Comet sounds & hashtags sub-resources, global /v1/sounds/*, Tracking list endpoints
C — count only, no totalInside data, under a resource-named keylimit, page (or offset), countno grand totalGET /v1/agents, GET /v1/agents/:id/runs
D — not paginatedInside datanone, or a plain countGET /v1/agents/:id/{benchmarks,affinity,activity,proposals}, GET /v1/trends/emerging

Shape A — nested list with offset

The list sits inside the data object under a key named after the resource (videos, slideshows, ads, outliers), alongside total, limit, and offset. This is what you get from an agent's (or Orbit/Comet's) video, slideshow, ad, and creator-outlier lists, and from the Satellite runs list. Creator/outlier lists additionally include a has_more boolean.

Use limit + offset (or page) to walk the pages. offset is the starting position: page 1 = offset 0, page 2 with limit=50 = offset 50.

Shape A — GET /v1/agents/:id/videos

{
  "data": {
    "agent_id": "2b1f9c3d-...",
    "agent_name": "Skincare Routine Research",
    "total": 283,
    "limit": 50,
    "offset": 0,
    "videos": [
      { "id": "e30b40b1-...", "url": "https://...", "views": 11166267 }
    ]
  }
}

Shape B — envelope with a pagination object

Here data is the array, and a sibling pagination object carries the metadata. This is the shape for sounds and hashtags sub-resources (on agents, Orbit, and Comet), the global /v1/sounds/* endpoints, and the Tracking list endpoints.

Drive it with limit + page. Use has_next_page / has_prev_page to know when to stop, and total_pages for a page count.

Shape B — GET /v1/sounds/trending

{
  "data": [
    { "id": "8f6e5c50-...", "title": "Saxophones getting louder" }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 850,
    "total_pages": 17,
    "has_next_page": true,
    "has_prev_page": false
  }
}

Shape C — count only, no grand total

GET /v1/agents and GET /v1/agents/:id/runs nest the array under a resource-named key inside data, with limit, page (or offset), and a count of items on the current page. There is no total, so you cannot precompute a page count.

Drive it with limit + page. Keep requesting the next page until a page returns fewer items than limit — that page is the last one.

Shape C — GET /v1/agents

{
  "data": {
    "limit": 50,
    "page": 1,
    "count": 3,
    "agents": [
      { "id": "2b1f9c3d-...", "name": "Skincare Routine Research", "is_recurring": true }
    ]
  }
}

Shape D — not paginated

A few endpoints return a complete, bounded result in one response — there is nothing to page through. Passing limit/page to them has no effect (except where a limit cap is documented on the endpoint itself).

This applies to an agent's benchmarks, affinity, activity, and proposals sub-resources, and to GET /v1/trends/emerging. Read data directly; don't look for pagination metadata.

Shape D — GET /v1/agents/:id/benchmarks

{
  "data": [
    {
      "follower_tier": "micro",
      "creator_count": 48,
      "median_followers": 42000,
      "median_engagement_rate": 0.071
    }
  ]
}

Was this page helpful?