---
title: "API pagination and filtering"
description: "How QuotWay API lists paginate: the list envelope, opaque cursors for quotes, starting_after for events, filters, and a safe incremental-sync recipe."
url: "https://www.quotway.com/de/docs/api/pagination"
type: "documentation"
category: "api"
updated: "2026-09-30"
locale: "de"
source: "QuotWay - B2B Quote & Negotiation App for Shopify"
---

# API pagination and filtering

**Read time:** 5 minutes.
**Who it's for:** Developers listing quotes or events.

## What does a list response look like?

Every list endpoint returns the same envelope:

```json
{
  "object": "list",
  "data": [ … ],
  "has_more": true,
  "next_cursor": "eyJ1IjoiMjAyNi0wOS0yOVQxNDoxMjowMC4wMDBaIiwiaSI6ImNsejhr…"
}
```

- `data` - up to `limit` items (default **20**, maximum **50**).
- `has_more` - `true` when there's another page.
- `next_cursor` - what to pass to get the next page; `null` on the last page.

## Paging through quotes - `GET /v1/quotes`

Pass `next_cursor` back as the `cursor` query parameter. The cursor is **opaque**: pass it back
unchanged, don't build or decode it, and keep the **same filters and sort** you used for the first
page. A cursor that can't be read returns `400 invalid_request` on the `cursor` field.

```bash
curl -G https://api.quotway.com/v1/quotes \
  -H "Authorization: Bearer $QUOTWAY_API_KEY" \
  --data-urlencode "limit=50" \
  --data-urlencode "cursor=eyJ1IjoiMjAyNi0wOS0yOVQxNDoxMjowMC4wMDBaIiwiaSI6ImNsejhr…"
```

### Sort

| `sort` | Order |
|---|---|
| `-updated_at` (default) | Most recently updated first |
| `updated_at` | Least recently updated first - use this for sync |

Ties on `updated_at` are broken by quote `id`, so paging never skips or repeats a quote that
doesn't change while you page.

### Filters

| Parameter | Example | Notes |
|---|---|---|
| `status` | `proposal_sent,countered` | Comma-separated [status values](/docs/api/quote-object#status). |
| `mode` | `b2b` | `wholesale` or `b2b`. |
| `updated_at[gte]` | `2026-09-01T00:00:00Z` | ISO-8601. |
| `updated_at[lte]` | `2026-09-30T23:59:59Z` | ISO-8601. |
| `created_at[gte]` | `2026-09-01T00:00:00Z` | ISO-8601. |
| `assigned_staff_id` | `clx…` | The `assigned_staff.id` of a staff member. |
| `po_number` | `PO-88213` | Exact match. |
| `customer_email` | `buyer@example.com` | Case-insensitive exact match. **Requires `read_customer_data`.** |

Unknown query parameters are ignored. Invalid values return `400 invalid_request` with one
`errors` entry per bad parameter. Brackets in parameter names must be URL-encoded (`%5B`, `%5D`)  - 
`curl -G --data-urlencode` does it for you.

Deleted quotes are never returned.

## Paging through events - `GET /v1/events` and `GET /v1/quotes/{id}/events`

Events are always **oldest first**, and paginate by event id: pass `next_cursor` (the last event's
id) as `starting_after`.

```bash
curl -G https://api.quotway.com/v1/events \
  -H "Authorization: Bearer $QUOTWAY_API_KEY" \
  --data-urlencode "type=quote.accepted,quote.partially_accepted" \
  --data-urlencode "starting_after=clz9m1a2b0004qw7hx8y9z0ab"
```

Event filters: `type` (comma-separated event types), `created[gte]`, `created[lte]`, `limit`.
Events are kept for 30 days; a `starting_after` id older than that returns `400 invalid_request`.
See [Events](/docs/api/events).

## Recipe: incremental quote sync

To keep an external system in step with QuotWay:

1. Store a **watermark** - the `updated_at` of the last quote you processed (start with a date far
   enough back to cover what you need).
2. Request `GET /v1/quotes?sort=updated_at&updated_at[gte]=<watermark>&limit=50`.
3. Upsert each quote by `id`, then follow `next_cursor` until `has_more` is `false`.
4. Save the largest `updated_at` you saw as the new watermark.
5. Repeat on a schedule - or, better, when a [webhook](/docs/api/webhooks) arrives.

Because the filter is `gte`, the quote at the watermark is fetched again next run. That's
deliberate: upserting by `id` makes it harmless, and it means a quote updated in the same
millisecond is never missed.

## Webhook endpoint lists

`GET /v1/webhooks` returns every endpoint in one page (a store can have at most 20), so `has_more`
is always `false` and `next_cursor` is always `null`.

## Related

- [The quote object](/docs/api/quote-object)
- [Events](/docs/api/events)
- [Rate limits](/docs/api/rate-limits)
