Pagination
List endpoints in the Mantis API support pagination to handle large result sets efficiently. This guide covers how to request paginated data and navigate through pages.
Query Parameters
Section titled “Query Parameters”All list endpoints accept these optional query parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
page | integer | 1 | >= 1 | Page number (1-indexed) |
limit | integer | 50 | 1-100 | Items per page |
Example Request
Section titled “Example Request”GET /api/v1/deployments?page=2&limit=25Authorization: Bearer <token>Query breakdown:
page=2- Get the second page of resultslimit=25- Return 25 items per page
Response Format
Section titled “Response Format”Paginated endpoints return results in a consistent envelope structure:
{ "data": [ { "id": "...", ... }, { "id": "...", ... }, // ... up to 'limit' items ], "meta": { "total": 247, "page": 2, "limit": 25, "total_pages": 10, "has_next": true, "has_prev": true }}Response Fields
Section titled “Response Fields”data (array)
- The actual items for the current page
- Array may be empty if page exceeds available data
- Maximum length is the requested
limit
meta (object)
total- Total number of items across all pagespage- Current page number (matches request)limit- Items per page (matches request)total_pages- Total number of pageshas_next-trueif there are more pages after this onehas_prev-trueif there are pages before this one
Pagination Logic
Section titled “Pagination Logic”Calculating Pages
Section titled “Calculating Pages”total_pages = ceil(total / limit)Example:
- Total items: 247
- Limit: 25
- Total pages:
ceil(247 / 25)= 10 pages
Page Numbers
Section titled “Page Numbers”- Pages are 1-indexed (first page is
page=1, notpage=0) - Requesting
page=0is treated aspage=1 - Requesting a page beyond
total_pagesreturns emptydataarray
Offset Calculation
Section titled “Offset Calculation”The API internally converts page numbers to database offsets:
offset = (page - 1) * limitExample for page 3 with limit 25:
offset = (3 - 1) * 25 = 50This skips the first 50 items and returns items 51-75.
Navigating Pages
Section titled “Navigating Pages”First Page
Section titled “First Page”GET /api/v1/deployments?page=1&limit=50# Or omit both parameters (defaults to page=1, limit=50)GET /api/v1/deploymentsNext Page
Section titled “Next Page”Use the has_next field to check if there’s a next page:
const response = await fetch('/api/v1/deployments?page=1&limit=50');const json = await response.json();
if (json.meta.has_next) { const nextPage = json.meta.page + 1; const nextResponse = await fetch( `/api/v1/deployments?page=${nextPage}&limit=50` );}Previous Page
Section titled “Previous Page”Use the has_prev field to check if there’s a previous page:
if (json.meta.has_prev) { const prevPage = json.meta.page - 1; const prevResponse = await fetch( `/api/v1/deployments?page=${prevPage}&limit=50` );}Last Page
Section titled “Last Page”Jump to the last page using total_pages:
GET /api/v1/deployments?page=10&limit=50# Where page=10 is from meta.total_pagesDefault Values
Section titled “Default Values”When pagination parameters are omitted, the API uses these defaults:
# These are equivalent:GET /api/v1/deploymentsGET /api/v1/deployments?page=1&limit=50Default values:
page:1(first page)limit:50items per page
Limits
Section titled “Limits”Maximum Page Size
Section titled “Maximum Page Size”The maximum limit is 100 items per page. Requests exceeding this are clamped:
# Request limit=500GET /api/v1/deployments?limit=500
# API automatically adjusts to limit=100{ "meta": { "limit": 100, # Clamped to maximum ... }}Minimum Page Size
Section titled “Minimum Page Size”The minimum limit is 1 item per page. Values less than 1 are adjusted:
# Request limit=0GET /api/v1/deployments?limit=0
# API adjusts to limit=1{ "meta": { "limit": 1, # Adjusted to minimum ... }}Endpoints Supporting Pagination
Section titled “Endpoints Supporting Pagination”These endpoints support pagination:
| Endpoint | Resource |
|---|---|
GET /api/v1/deployments | Deployments |
GET /api/v1/actions | Actions |
GET /api/v1/sequences | Sequences |
GET /api/v1/solutions | Solutions |
GET /api/v1/targets | Targets |
GET /api/v1/environments | Environments |
GET /api/v1/tenants | Tenants |
GET /api/v1/admin/users | Users |
GET /api/v1/admin/roles | Roles |
GET /api/v1/tags | Tags |
GET /api/v1/deployment-freezes | Deployment freezes |
GET /api/v1/audit/logs | Audit logs |
Examples
Section titled “Examples”Fetching All Items (Batch)
Section titled “Fetching All Items (Batch)”To retrieve all items across multiple pages:
async function fetchAllDeployments(baseUrl, token) { const allDeployments = []; let page = 1; let hasNext = true;
while (hasNext) { const response = await fetch( `${baseUrl}/api/v1/deployments?page=${page}&limit=100`, { headers: { Authorization: `Bearer ${token}` }, } );
const json = await response.json(); allDeployments.push(...json.data);
hasNext = json.meta.has_next; page++; }
return allDeployments;}Python Example
Section titled “Python Example”import requestsfrom typing import List, Dict, Any
def fetch_all_deployments(base_url: str, token: str) -> List[Dict[str, Any]]: """Fetch all deployments across all pages.""" all_deployments = [] page = 1 has_next = True
while has_next: response = requests.get( f"{base_url}/api/v1/deployments", params={"page": page, "limit": 100}, headers={"Authorization": f"Bearer {token}"} ) response.raise_for_status()
data = response.json() all_deployments.extend(data["data"])
has_next = data["meta"]["has_next"] page += 1
return all_deploymentsDisplaying Page Navigation (React)
Section titled “Displaying Page Navigation (React)”import React from 'react';
interface PaginationProps { meta: { page: number; total_pages: number; has_next: boolean; has_prev: boolean; }; onPageChange: (page: number) => void;}
export const Pagination: React.FC<PaginationProps> = ({ meta, onPageChange }) => { return ( <div className="pagination"> <button disabled={!meta.has_prev} onClick={() => onPageChange(meta.page - 1)} > Previous </button>
<span> Page {meta.page} of {meta.total_pages} </span>
<button disabled={!meta.has_next} onClick={() => onPageChange(meta.page + 1)} > Next </button> </div> );};Performance Considerations
Section titled “Performance Considerations”Large Result Sets
Section titled “Large Result Sets”For very large result sets (10,000+ items):
- Use filters - Most list endpoints support filtering to reduce total items
- Increase page size - Use
limit=100to minimize requests - Cache results - Cache pages client-side to avoid repeated requests
- Consider streaming - For real-time data, use SSE endpoints instead
Deep Pagination
Section titled “Deep Pagination”Fetching very high page numbers (e.g., page 1000) can be slow because the database must skip many rows. Performance degrades with offset size.
Better approaches:
- Use filters to reduce result set
- Implement cursor-based pagination (if your use case requires it, contact support)
- Consider if you need all pages (users rarely browse beyond page 10)
Filtering + Pagination
Section titled “Filtering + Pagination”Many endpoints support filtering parameters in addition to pagination:
# Get page 2 of deployments, text-filtered (search matches name + status)GET /api/v1/deployments?page=2&limit=25&search=running
# Get page 1 of targets, text-filtered (search matches name + hostname)GET /api/v1/targets?page=1&limit=50&search=webNote: Filters reduce the total count in meta. The pagination applies to the filtered subset, not all items.
Empty Pages
Section titled “Empty Pages”Requesting a page beyond the available data returns an empty array:
GET /api/v1/deployments?page=999&limit=50Response:
{ "data": [], "meta": { "total": 247, "page": 999, "limit": 50, "total_pages": 5, "has_next": false, "has_prev": true }}Best Practices
Section titled “Best Practices”1. Check has_next Before Fetching
Section titled “1. Check has_next Before Fetching”Don’t blindly increment page numbers. Always check the has_next field:
// ❌ Bad - may fetch empty pagesfor (let page = 1; page <= 100; page++) { await fetchPage(page);}
// ✅ Good - stops at last pagelet page = 1;do { const response = await fetchPage(page); // Process response.data if (!response.meta.has_next) break; page++;} while (true);2. Use Appropriate Page Sizes
Section titled “2. Use Appropriate Page Sizes”- UI pagination:
limit=25-50(fast page loads) - Batch processing:
limit=100(fewer requests) - Initial load:
limit=10(quick first paint)
3. Handle Empty Results
Section titled “3. Handle Empty Results”Always handle the case where data is empty:
const response = await fetch('/api/v1/deployments?page=5');const json = await response.json();
if (json.data.length === 0) { console.log('No deployments on this page');}4. Preserve Filters When Paginating
Section titled “4. Preserve Filters When Paginating”When navigating pages, maintain any active filters:
function buildUrl(page, filters) { const params = new URLSearchParams({ page: page.toString(), limit: '50', ...filters, }); return `/api/v1/deployments?${params}`;}Troubleshooting
Section titled “Troubleshooting”Page Parameter Ignored
Section titled “Page Parameter Ignored”Symptom: Always getting the first page regardless of page parameter.
Cause: Query parameter not properly encoded or parsed.
Solution: Verify URL encoding:
const url = new URL('https://mantis.example.com/api/v1/deployments');url.searchParams.set('page', '2');url.searchParams.set('limit', '50');fetch(url);Inconsistent Total Counts
Section titled “Inconsistent Total Counts”Symptom: total changes between requests.
Cause: Data is being added/deleted between pagination requests.
Solution: This is expected behavior. For consistent pagination snapshots, consider implementing cursor-based pagination for your use case.
Missing Metadata
Section titled “Missing Metadata”Symptom: Response doesn’t include meta field.
Cause: Endpoint doesn’t support pagination, or you’re hitting a detail endpoint (not a list endpoint).
Solution: Verify you’re calling a list endpoint (e.g., /deployments not /deployments/{id}).
Next Steps
Section titled “Next Steps”- Deployments API - Apply pagination to deployments
- Error Handling - Handle pagination errors
- Authentication - Authenticate your requests
