Skip to main content

Pagination

All list endpoints in the Typograph API use offset-based pagination with a consistent response format.

Query Parameters

ParameterTypeDefaultDescription
limitinteger10-20Number of items per page
offsetinteger0Number of items to skip

Limit Constraints

  • Minimum: 1
  • Maximum: 50 (per endpoint)
  • Default: Varies by endpoint (typically 10 or 20)

Exceeding the maximum limit returns a 400 Bad Request error:

{
"error": "invalid_request",
"error_description": "The limit can't be greater than 50."
}

Response Format

All paginated endpoints return a standardized response structure:

{
"data": [
{ "id": "...", "name": "..." },
{ "id": "...", "name": "..." }
],
"meta": {
"total": 150,
"limit": 20,
"offset": 0,
"has_more": true
}
}

Response Fields

FieldTypeDescription
dataarrayArray of resource objects
meta.totalintegerTotal number of items available
meta.limitintegerNumber of items requested per page
meta.offsetintegerNumber of items skipped
meta.has_morebooleanWhether more items exist beyond this page

Usage Examples

First Page

curl "https://api.typograph.nl/v1/file/projects?limit=20&offset=0" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{
"data": [...],
"meta": {
"total": 150,
"limit": 20,
"offset": 0,
"has_more": true
}
}

Next Page

curl "https://api.typograph.nl/v1/file/projects?limit=20&offset=20" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{
"data": [...],
"meta": {
"total": 150,
"limit": 20,
"offset": 20,
"has_more": true
}
}

Last Page

When you reach the last page, has_more will be false:

{
"data": [...],
"meta": {
"total": 150,
"limit": 20,
"offset": 140,
"has_more": false
}
}

Iterating Through All Results

JavaScript/TypeScript

async function getAllItems(endpoint: string, token: string) {
const items = [];
let offset = 0;
const limit = 50; // Maximum allowed

while (true) {
const response = await fetch(
`${endpoint}?limit=${limit}&offset=${offset}`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const { data, meta } = await response.json();

items.push(...data);

if (!meta.has_more) break;
offset += limit;
}

return items;
}

PHP

function getAllItems(string $endpoint, string $token): array
{
$items = [];
$offset = 0;
$limit = 50; // Maximum allowed

do {
$response = $client->request('GET', "{$endpoint}?limit={$limit}&offset={$offset}", [
'headers' => ['Authorization' => "Bearer {$token}"],
]);

$result = json_decode($response->getContent(), true);
$items = array_merge($items, $result['data']);
$hasMore = $result['meta']['has_more'];
$offset += $limit;
} while ($hasMore);

return $items;
}

Best Practices

Choose an Appropriate Page Size

Use CaseRecommended Limit
Initial page load10-20
Infinite scroll20-30
Data export/sync50 (maximum)
Search results10-20

Handle Edge Cases

  1. Empty Results: When total is 0, data will be an empty array
  2. Invalid Offset: If offset exceeds total, returns empty data with has_more: false
  3. Concurrent Updates: Items may shift between pages if data changes during pagination

Efficient Pagination

  • Cache Total Count: The total value can help display page numbers or progress indicators
  • Use Maximum Limit for Exports: When syncing all data, use limit=50 to minimize requests
  • Check has_more: More reliable than calculating from offset + length vs total

Endpoints Supporting Pagination

EndpointDefault LimitMax Limit
GET /v1/file/projects1050
GET /v1/file/templates1050
GET /v1/file/projects/{projectId}/uploads1050
GET /v1/file/teams1050
GET /v1/publisher/jobs1050
GET /v1/converter/jobs1050
GET /v1/webhook/subscriptions2050
GET /v1/webhook/subscriptions/{id}/deliveries2050
GET /v1/identity/oauth/clients1050