Pagination and formats
Every list returns the same envelope, so one helper in your client covers all of them. Reports and statutory files answer JSON by default and a file when you ask for one.
List envelope
{
"data": [ ... ],
"meta": { "page": 1, "per_page": 50, "total": 128, "total_pages": 3 }
}page starts at 1 and per_page defaults to 50, capped at 200. Ask for the next page while page < total_pages.
Syncing incrementally
GET /employees?updated_since=2026-09-01T00:00:00Z returns only what changed, which is how you keep a local copy in step without re-reading the master every night. Better still, subscribe to employee.upserted and stop polling.
File formats
Report and statutory endpoints take ?format= and return the same content as a file. Omit it - or send Accept: application/json - and you get rows you can render yourself.
| format | Content type | Typical use |
|---|---|---|
| json | application/json | Render it in your own UI. |
| xlsx | Office spreadsheet | Hand it to a finance team. |
| csv | text/csv | Bank uploads and warehouse loads. |
| txt | text/plain | Fixed-width portal formats: the PF ECR, the 24Q FVU file. |
| application/pdf | Payslips, PF statements, salary certificates. |
curl -L 'https://api.indpayroll.com/v1/statutory/pf/ecr?month=9&year=2026&format=txt' \
-H "Authorization: Bearer $INDP_API_KEY" \
-o pf-ecr-2026-09.txt