Working with pagination
Introduction to Pagination in Moneybird
When working with the Moneybird API, you’ll often need to retrieve collections of resources like contacts, invoices, or financial mutations. The Moneybird API limits the number of items returned in a single response to prevent performance issues. By default, each page contains up to 100 items.
Pagination Support Across Endpoints
It’s essential to understand that pagination is implemented differently across Moneybird API endpoints:
Endpoints with True API Pagination
These endpoints support true pagination with page
and per_page
parameters:
contacts()
- Supports true API pagination through the/contacts
endpointsalesInvoices()
- Supports true API pagination through the/sales_invoices
endpointrecurringSalesInvoices()
- Supports true API pagination through the/recurring_sales_invoices
endpointexternalSalesInvoices()
- Supports true API paginationestimates()
- Supports true API paginationgeneralDocuments()
- Supports true API paginationreceipts()
- Supports true API pagination
Endpoints Limited to 100 Records
For these endpoints, the all()
method will only return up to 100 records. If you need more, use the synchronization API:
financialMutations()
- Limited to 100 records per the API documentationpayments()
- Limited records, requires synchronization for moreprojects()
- Limited records, requires synchronization for morepurchaseTransactions()
- Limited records, requires synchronization for moreproducts()
- Limited records, requires synchronization for more
Endpoints Without Pagination
These endpoints do not support pagination in the Moneybird API and will always return the full dataset:
ledgerAccounts()
financialAccounts()
Using the SDK’s Pagination Methods
This SDK mirrors the Moneybird API as closely as possible:
- For endpoints with true API pagination, the SDK provides the
paginate()
method - For endpoints with limited records, the SDK provides both
all()
and synchronization methods
Using the Paginator
The paginate()
method returns a MoneybirdPaginator
object that implements PHP’s Iterator
interface, allowing you to easily loop through all items across multiple pages:
// Get a paginator for contacts, no requests are made yet$contacts = $client->contacts()->paginate();
// Iterate through all contacts across all pagesforeach ($contacts as $contact) { echo $contact->company_name . "\n"; // Process each contact}
The paginator automatically handles fetching the next page of results when needed, so you don’t have to worry about page numbers or making additional API calls manually.
Using the All Method
For other endpoints, you can use the all()
method to retrieve a collection of records in a single request:
// Getting all items at once (simpler but may be inefficient for large datasets)$allFinancialMutations = $client->financialMutations()->all();
Using the Synchronization API
For some endpoints, you should use the synchronization API to retrieve more data:
// Step 1: Get IDs and versions for synchronization// This returns an array of IdVersion objects with id and version properties$idVersions = $client->financialMutations()->synchronization();
// Step 2: Check what mutations need updating in your system$idsToUpdate = array_filter($idVersions, function($idVersion) use ($knownVersion) { // Compare $idVersion->version with your stored version // Return true if the version is newer and needs updating return $idVersion->version > $knownVersion;});
$idsToFetch = array_map(fn($idVersion) => $idVersion->id, $idsToUpdate);
// Step 3: Fetch only the records that need updating// Returns a maximum of 100 financial mutations, even if more ids are provided.$client->financialMutations()->synchronize($idsToFetch);
Best Practices
-
Use Pagination for Large Collections: When available, always use the
paginate()
method when dealing with potentially large collections of items. -
Avoid Unnecessary Iterations: If you only need to process a few items, consider using filters to reduce the dataset before pagination.
-
Handle Rate Limits: Be aware that each page request counts toward your API rate limits. If you’re processing many pages, consider adding delays between requests.
-
Error Handling: Implement proper error handling to deal with potential API errors during pagination:
Example: Exporting All Contacts to CSV
Here’s a practical example of using pagination to export all contacts to a CSV file:
// Open a file for writing$file = fopen('contacts_export.csv', 'w');
// Write CSV headerfputcsv($file, ['ID', 'Company Name', 'First Name', 'Last Name', 'Email', 'Phone']);
try { // Get paginator for contacts $contacts = $client->contacts()->paginate();
// Iterate through all pages of contacts foreach ($contacts as $contact) { fputcsv($file, [ $contact->id, $contact->company_name ?? '', $contact->firstname ?? '', $contact->lastname ?? '', $contact->email ?? '', $contact->phone ?? '', ]); }} catch (\Exception $e) { echo "Error exporting contacts: " . $e->getMessage();}
// Close the filefclose($file);
echo "Export complete!";
This example efficiently processes all contacts regardless of how many there are, writing them to a CSV file one page at a time.