Pagination

How list endpoints page through results, default limits, and how to fetch more than the default page.

The Qyvo REST API today returns flat arrays with hard limits per endpoint, not cursor-paginated envelopes. This is intentional: the trigger and search endpoints are designed for polling agents (n8n, Zapier, Claude) that want the most recent N records on each call.

Default limits per endpoint

Endpoint Default limit Sort Filter params
GET /v1/triggers/new-message-received 100 created_at DESC message_type
GET /v1/triggers/new-campaign-sent 100 created_at DESC
GET /v1/triggers/new-flow-triggered 100 created_at DESC flow_id
GET /v1/triggers/new-sequence-triggered 100 created_at DESC sequence_id
POST /v1/actions/search-contacts 50 last_message_at DESC query, tag, email
POST /v1/actions/list-templates All (capped server-side) name status
POST /v1/actions/list-tags All (capped server-side) name name

Polling pattern

For triggers, the right pattern is to remember the most recent id you've seen and stop processing when you reach it again on the next poll. Pseudocode:

last_seen_id = load_from_state()

batch = GET /v1/triggers/new-message-received
new_messages = []
for msg in batch:
    if msg.id == last_seen_id:
        break
    new_messages.append(msg)

process(new_messages)
if new_messages:
    save_to_state(new_messages[0].id)

This is exactly what the n8n trigger node does internally. Don't poll faster than every 30 seconds unless your account has a raised rate limit.

Larger result sets

If you genuinely need more than 100 records (e.g. exporting all contacts), use the MCP tools instead — list_contacts supports cursor pagination via page and per_page parameters. See MCP tool reference: Contacts.

For ad-hoc bulk exports, the dashboard offers a CSV export under Contacts → Export.

Filter behaviour

Filters are AND-combined. Empty strings are treated as "no filter":

# Returns up to 50 contacts whose name/phone/email matches "smith" AND who have the tag "vip"
curl -X POST https://www.qyvo.io/api/v1/actions/search-contacts \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "smith", "tag": "vip"}'

There is no OR operator on the REST surface. Compose two requests on the client side and dedupe by id if you need disjunction.

Future direction

Cursor-based pagination (?cursor=...) is on the roadmap for triggers and search endpoints when account-level workloads outgrow flat polling. We'll keep current behaviour as the default and gate cursors behind an opt-in ?paginate=cursor flag for backwards compatibility.