Skip to content

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:

{
  "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.

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.
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.

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.

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 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.

Still need a hand? The team is happy to help.

We’d like to set analytics cookies to understand how the site is used. They’re not required — declining changes nothing about how the site works, and you can change your mind any time on our privacy page.