Skip to content
Last updated

Pagination

Learn how to paginate through list results using cursor-based pagination.

Overview

All filter endpoints in the MVMNT API use cursor-based pagination to efficiently retrieve large result sets. Pagination is consistent across all resource types (orders, vendors, carriers, customers, etc.).

How It Works

Request Format

Filter endpoints use POST requests with pagination parameters in the request body:

POST /v1/vendors/filter
Content-Type: application/json

{
  "filter": { ... },
  "pageSize": 50,
  "cursor": null
}

Response Format

All paginated responses return a consistent structure:

{
  "data": [
    { "id": "...", "name": "..." },
    { "id": "...", "name": "..." }
  ],
  "pageInfo": {
    "pageSize": 50,
    "hasNextPage": true,
    "hasPreviousPage": false,
    "endCursor": "eyJpZCI6IjU1MGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAwMCJ9"
  }
}

Pagination Parameters

pageSize

Type: Integer Default: 50 Range: 1 - 250 Description: Number of results to return per page

{
  "pageSize": 100
}

cursor

Type: String (nullable) Default: null Description: Opaque cursor token from previous response's pageInfo.endCursor

{
  "cursor": "eyJpZCI6IjU1MGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAwMCJ9"
}

First page: Omit cursor or set to null Subsequent pages: Use endCursor from previous response

PageInfo Object

The pageInfo object in every response provides pagination metadata:

FieldTypeDescription
pageSizeintegerNumber of items in current page
hasNextPagebooleanWhether more results are available
hasPreviousPagebooleanWhether previous page exists
endCursorstringCursor for next page (null if no next page)

Basic Example

Fetch First Page

curl -X POST https://api.mvmnt.io/v1/vendors/filter \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "status": { "equalTo": "ACTIVE" }
    },
    "pageSize": 50
  }'

Response:

{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "friendlyId": "V100001",
      "name": "ABC Warehouse",
      "status": "ACTIVE"
    },
    {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "friendlyId": "V100002",
      "name": "XYZ Storage",
      "status": "ACTIVE"
    }
    // ... 48 more results
  ],
  "pageInfo": {
    "pageSize": 50,
    "hasNextPage": true,
    "hasPreviousPage": false,
    "endCursor": "eyJpZCI6IjY2MGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAwMSJ9"
  }
}

Fetch Next Page

Use endCursor from the previous response:

curl -X POST https://api.mvmnt.io/v1/vendors/filter \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "status": { "equalTo": "ACTIVE" }
    },
    "pageSize": 50,
    "cursor": "eyJpZCI6IjY2MGU4NDAwLWUyOWItNDFkNC1hNzE2LTQ0NjY1NTQ0MDAwMSJ9"
  }'

Last Page

When hasNextPage is false, you've reached the end:

{
  "data": [
    // ... remaining results
  ],
  "pageInfo": {
    "pageSize": 50,
    "hasNextPage": false,
    "hasPreviousPage": true,
    "endCursor": null
  }
}

Best Practices

✅ Do

  • Use maximum page size for batch processing: Set pageSize: 250 when fetching all results
  • Store cursor tokens temporarily: Only valid for the current query, don't persist long-term
  • Handle hasNextPage correctly: Always check hasNextPage instead of checking if data is empty
  • Preserve filter criteria: Use identical filter on all pages of a query
  • Implement retry logic: Network failures can occur during pagination

❌ Don't

  • Don't use offset-based pagination: MVMNT uses cursor-based pagination, not page numbers
  • Don't modify filters mid-pagination: Using different filters with the same cursor produces undefined results
  • Don't persist cursors: Cursors may expire or become invalid over time
  • Don't assume page size matches result count: Last page may have fewer results
  • Don't paginate unnecessarily: If you need all results, fetch them in one efficient loop

Troubleshooting

Empty Results on First Page

Problem: data array is empty but no error

Possible Causes:

  1. Filter criteria matches no records
  2. All matching records are deleted (see Soft Deletes)

Solutions:

  1. Verify filter criteria
  2. Check if records exist using less restrictive filters
  3. Include deleted records if needed (see Filtering)

Invalid Cursor Error

Problem: API returns error: "Invalid cursor"

Possible Causes:

  1. Cursor from a different query (different filter/sort)
  2. Cursor expired (very old cursor)
  3. Malformed cursor string

Solutions:

  1. Always use cursor from the same filter query
  2. Don't persist cursors - start fresh queries with cursor: null
  3. Ensure cursor is passed as-is without modification

Duplicate Results

Problem: Same record appears in multiple pages

Possible Causes:

  1. Records were created/modified during pagination
  2. Using cursors from different queries

Solutions:

  1. Accept eventual consistency for real-time data
  2. Deduplicate results by ID on client side
  3. For consistent snapshots, consider using timestamps in filters

Page Size Ignored

Problem: Receiving different number of results than requested

Possible Causes:

  1. Last page has fewer results
  2. pageSize exceeds maximum (250)
  3. Some records filtered out after query

Solutions:

  1. Check pageInfo.hasNextPage instead of counting results
  2. Ensure pageSize is between 1-250
  3. This behavior is normal and expected

Next Steps

  • Filtering - Learn how to filter results before pagination
  • Soft Deletes - Understand how deleted records affect pagination
  • API Reference - See pagination on specific endpoints