Pagination
Navigate large result sets with page-and-limit pagination.
Query Parameters
The three list endpoints (/articles, /social/content, /projects) all accept the same two pagination parameters. There is no offset or cursor pagination.
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 | Page number, 1-indexed. Minimum 1. |
| limit | integer | 20 | Results per page. Minimum 1, maximum 100. |
Values outside these ranges are rejected with a 400 VALIDATION_ERROR rather than being clamped.
Response Format
Every paginated response includes a pagination object alongside the data array, providing all the information you need to navigate through result pages.
{
"success": true,
"data": [
"..."
],
"pagination": {
"total": 142,
"page": 2,
"limit": 20,
"total_pages": 8,
"has_more": true
},
"meta": {
"timestamp": "2026-02-01T12:00:00Z"
}
}Pagination Fields
| Field | Type | Description |
|---|---|---|
| total | integer | Total number of matching records |
| page | integer | Current page number |
| limit | integer | Results per page |
| total_pages | integer | Total number of pages |
| has_more | boolean | Whether more pages exist after the current one |
Iterating All Pages
To fetch all records, loop through pages until has_more is false:
async function fetchAllArticles(apiKey) {
const articles = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const res = await fetch(
`https://www.brainpercent.app/api/v1/articles?page=${page}&limit=100`,
{ headers: { 'Authorization': `Bearer ${apiKey}` } }
);
const { data, pagination } = await res.json();
articles.push(...data);
hasMore = pagination.has_more;
page++;
}
return articles; // All articles
}Sorting
Only /articles takes sort and order. The other two list endpoints always return newest first.
| Endpoint | Ordering |
|---|---|
| /api/v1/articles | sort: created_at (default), updated_at, title. order: asc or desc (default desc). |
| /api/v1/social/content | Fixed: created_at descending |
| /api/v1/projects | Fixed: created_at descending |
Filters available alongside pagination: /articles takes status, project_id, and search; /social/content takes platform, status, article_id, and project_id; /projects takes status and search.
// Get newest articles first (default)
const res = await fetch(
'https://www.brainpercent.app/api/v1/articles?sort=created_at&order=desc',
{ headers: { 'Authorization': 'Bearer bp_your_key' } }
);
// Get articles alphabetically
const res2 = await fetch(
'https://www.brainpercent.app/api/v1/articles?sort=title&order=asc',
{ headers: { 'Authorization': 'Bearer bp_your_key' } }
);Combining Filters with Pagination
Filter parameters can be combined with pagination and sorting to narrow down results efficiently:
// Get finished articles from a specific project, page 2.
// 'cms' is the completed status. There is no 'published' status.
const res = await fetch(
'https://www.brainpercent.app/api/v1/articles?status=cms&project_id=d290f1ee-6c54-4b01-90e6-d701748f0851&page=2&limit=25&sort=updated_at&order=desc',
{ headers: { 'Authorization': 'Bearer bp_your_key' } }
);
// Social posts that already have an Instagram variant, newest first.
const social = await fetch(
'https://www.brainpercent.app/api/v1/social/content?platform=instagram&status=ready&limit=50',
{ headers: { 'Authorization': 'Bearer bp_your_key' } }
);Best Practices
- Use
limit=100(maximum) when fetching all records to minimize requests - Always check
has_morerather than comparingpagetototal_pages - Add a small delay between page requests to respect rate limits
- Cache total counts if you only need them for display purposes
- Use filters to reduce result sets before paginating