Pagination guide
The Partner API uses four response shapes. Pick the row that matches your endpoint before writing client code.
Decision tree
Is the endpoint a list (GET collection)?
├─ No → single object (no pagination)
├─ Yes → Does OpenAPI show `cursor` instead of `page`?
│ ├─ Yes → CURSOR (timesheet_idle_times only)
│ └─ No → Does the 200 schema describe a bare array?
│ ├─ Yes → BARE ARRAY (screenshots, payment_settings)
│ └─ No → OFFSET envelope
│ ├─ limit max 100 → standard (default 50)
│ └─ limit max 20 → report tier (default 20)Shape reference
1. Offset envelope (standard)
Used by: organization, project, payroll, leaves, and suspicious-activity list endpoints.
| Parameter | Default | Max |
|---|---|---|
page | 1 | — |
limit | 50 | 100 |
Response:
{
"count": 42,
"next": "https://api.apploye.com/v1/members/?page=2&limit=50",
"previous": null,
"results": [ ... ]
}Walk pages with page until next is null. count is the total across all pages.
2. Offset envelope (report tier)
Used by: time_activity_reports, manual_timesheet_reports, clockinouts, app_reports, url_reports.
Same envelope as standard offset, but tighter limits because each row carries aggregated or nested data:
| Parameter | Default | Max |
|---|---|---|
page | 1 | — |
limit | 20 | 20 |
3. Cursor envelope
Used by: GET /v1/timesheet_idle_times/ only.
Do not send page. Use cursor from the prior response.
| Parameter | Default | Max | Notes |
|---|---|---|---|
limit | 10 | 20 | Max users per request |
cursor | — | — | Opaque token from pagination.next_cursor |
Response:
{
"results": [
{
"user": { "user_id": "...", "email": "..." },
"timesheets": [ { "id": "...", "idle_times": [] } ]
}
],
"pagination": {
"limit": 10,
"timesheets_cap": 1000,
"users_returned": 1,
"timesheets_returned": 42,
"total_users": 85,
"has_more": true,
"next_cursor": "eyJ..."
}
}Walking pages:
- Call without
cursorfor the first page. - If
pagination.has_moreistrue, passpagination.next_cursorascursoron the next request. - Repeat until
has_moreisfalse.
Timesheet cap: at most 1,000 timesheets per response. Users are never split across pages.
Common errors:
| Situation | Response |
|---|---|
Sending page on this endpoint | 400 — use cursor instead |
limit > 20 | 400 VALIDATION_ERROR |
See ADR-023 for why timesheets use cursor pagination.
4. Bare array
Used by: GET /v1/screenshots/, GET /v1/members/{user_id}/payment_settings/.
Returns [...] with no count, next, or pagination wrapper. Result sets are bounded by required filters (user + date for screenshots).
Endpoint matrix
| Operation | Path | Shape | Default limit | Max limit |
|---|---|---|---|---|
listTimesheetIdleTime | /v1/timesheet_idle_times/ | Cursor | 10 users | 20 users |
listMembers | /v1/members/ | Offset standard | 50 | 100 |
listClients | /v1/clients/ | Offset standard | 50 | 100 |
listTeams | /v1/teams/ | Offset standard | 50 | 100 |
listTeamMembers | /v1/teams/{team_id}/members/ | Offset standard | 50 | 100 |
listProjects | /v1/projects/ | Offset standard | 50 | 100 |
listProjectMembers | /v1/projects/{project_id}/members/ | Offset standard | 50 | 100 |
listProjectTasks | /v1/projects/{project_id}/tasks/ | Offset standard | 50 | 100 |
listClientProjects | /v1/clients/{client_id}/projects/ | Offset standard | 50 | 100 |
listMemberProjects | /v1/members/{user_id}/projects/ | Offset standard | 50 | 100 |
listProjectMemberships | /v1/project_memberships/ | Offset standard | 50 | 100 |
listTasks | /v1/tasks/ | Offset standard | 50 | 100 |
listTaskMembers | /v1/tasks/{task_id}/members/ | Offset standard | 50 | 100 |
listInvoices | /v1/invoices/ | Offset standard | 50 | 100 |
listMemberHourlyPaymentLog | /v1/members/{user_id}/hourly_payment_logs/ | Offset standard | 50 | 100 |
listMemberOneTimePaymentLog | /v1/members/{user_id}/one_time_payment_logs/ | Offset standard | 50 | 100 |
listMemberPayables | /v1/members/{user_id}/payables/ | Offset standard | 50 | 100 |
listSuspiciousActivityLogs | /v1/suspicious_activity_logs/ | Offset standard | 50 | 100 |
listLeaveApplications | /v1/leave_applications/ | Offset standard | 50 | 100 |
listLeaveTypes | /v1/leave_types/ | Offset standard | 50 | 100 |
listLeavePolicies | /v1/leave_policies/ | Offset standard | 50 | 100 |
listLeavePeriods | /v1/leave_periods/ | Offset standard | 50 | 100 |
listLeaveBalances | /v1/leave_balances/ | Offset standard | 50 | 100 |
listLeaveAssignments | /v1/leave_assignments/ | Offset standard | 50 | 100 |
listTimeActivityReport | /v1/time_activity_reports/ | Offset report | 20 | 20 |
listManualTimesheetReports | /v1/manual_timesheet_reports/ | Offset report | 20 | 20 |
listClockInOut | /v1/clockinouts/ | Offset report | 20 | 20 |
listAppReports | /v1/app_reports/ | Offset report | 20 | 20 |
listUrlReports | /v1/url_reports/ | Offset report | 20 | 20 |
listScreenshots | /v1/screenshots/ | Bare array | — | — |
listMemberPaymentSettings | /v1/members/{user_id}/payment_settings/ | Bare array | — | — |
Retrieve endpoints (retrieveOrganization, retrieveClient, …) return a single object — no pagination parameters.
Offset stability note
Entity lists (members, projects, clients) may show duplicates or gaps if rows are inserted or deleted between page requests. This is accepted for admin-style paging. For high-churn data syncs, use updated_since polling on supported endpoints or cursor pagination on timesheets.
Related docs
- Quickstart
- API Reference —
OffsetPaginatedEnvelope,CursorPaginatedEnvelope
