About paging
When getting lists of data from API-endpoints it will be most efficient for both the client and server to divide the result into portions instead of getting all the data returned at once. The Visma.net API supports this by implementing a method called paging. Paging means that when you request lists of data you should also provide two extra query-parameters called pageSize and pageNumber.
pageSize: The maximum number of records you want to have returned on each page (the length of each page) pageNumber: The page you are requesting.
Example In the database you have 350 customers, you make a GET request to the Customer-endpoint to get all these. To limit the number of customers received you can divide this into pages that contain upto 100 customer (pageSize=100). To get the complete list you then have to make 4 requests to the Customer-endpoint:
Request
Result
1
GET /customer?pageSize=100&pageNumber=1
Returns the first 100 customers (1-100)
2
GET /customer?pageSize=100&pageNumber=2
Returns the second page of 100 customers (101-200)
3
GET /customer?pageSize=100&pageNumber=3
Returns the third page of 100 customers (201-300)
4
GET /customer?pageSize=100&pageNumber=4
Returns the last page of remaining customers (301-350)
Paging is implemented on all GET endpoints that returns lists in the Visma.net API. It is mandatory to use the parameters pageSize and pageNumber in all requests to endpoints that support this.
How paging is implemented in Visma.net API
For all endpoints that return lists paging is implemented by providing two queryparameters, pageSize and pageNumber. For all endpoints these parameters are documented in the swagger documentation (https://integration.visma.net/API-index/). For all endpoints that provide these parameters it is important that your integration provide these for all requests. If not provided default-values will be used and you will potentially not receive the complete resultset. In the swagger-documentation you can see the default-value for the specific endpoint.
Default parameter values
Parameter
Default value (if not provided)
pageNumber
1
pageSize
Can vary from endpoint to endpoint, can also change over time.
Maximum value for the pageSize parameter is bound to the default-value that will also represent the maximum value allowed. Meaning that if you specify a value in pageSize that is greater than the default value, the endpoint will only return the number of records defined by the default value for pageSize in this endpoint.
In addition to swagger-documentation the maximum allowed value for pageSize will also be returned as part of the metadata-property in the returned JSON-data. The value will have the name maxPageSize.
"metadata": {
"totalCount": 450,
"maxPageSize": 500
}
Metadata
As part of every request to an endpoint that supports paging you will get a metadata-property returned as part of the returned JSON-data. This metadata is provided to give your integration information about the available results and restrictions of the current request. The metadata-property will provide the following values:
"metadata": {
"totalCount": 450,
"maxPageSize": 500
}
Value
Description
totalCount
The total number of results for the current request regardless of pages.
Example:
GET /customer?name=Norwegian?pageSize=5&pageNumber=1
This request will return the first page of 5 customers with the name containing “Norwegian”. However, in the database there are 12 customers with names containing “Norwegian”, so the totalCount will have the value 12.
maxPageSize
The maximum pageSize you can set for this endpoint. If you specify a number higher than this, the result will be restricted to only return the maxPageSize number of records.
You can use the values in the metadata to calculate the number of pages you need to get in order to receive the whole result-set based on the pageSize you are using.
Paging in combination with filters
Most GET-endpoints in the API contain filter-parameters. These are used to narrow down the resultset to only contain the records that are relevant to the request. It is important to notice that when these filter-parameters are used in combination with the paging-parameters, the resultset is defined as the total resultset for the specified filter-parameters. This means that if the resultset spans across multiple pages, the exact same filter-parameters must be specified for all subsequent requests to get the following pages. The Visma.net API contains no state to store what pages/records have been delivered, so every request will be handled independent of previous requests. The figure below illustrates what results will be included in each page based on three different queries with different values for parameters lastModifiedDateTime and pageSize.
Query 1:
?lastModifiedDateTime=2020-03-01T00:00:00&lastModifiedDateTimeCondition=>=&pageSize=3 The resultset will be divided into 4 different pages, meaning that you have to make 4 requests to the API, with the exact same values for parameter lastModifiedDateTime, lastModifiedDateTimeCondition and pageSize. The pageNumber-parameter will define what results you will get, marked by the numbers 1-4 and the colors yellow, pink, green and blue in the figure.
Query 2: ?lastModifiedDateTime=2020-03-01T00:00:00&lastModifiedDateTimeCondition=>=&pageSize=5
The resultset will be divided into 2 different pages, meaning that you have to make 2 requests to the API, with the exact same values for parameter lastModifiedDateTime, lastModifiedDateTimeCondition and pageSize. The pageNumber-parameter will define what results you will get, marked by the numbers 1-2 and the colors green and purple in the figure.
Query 3: ?lastModifiedDateTime=2020-03-06T00:00:00&lastModifiedDateTimeCondition=>=&pageSize=3
The resultset will be divided into 2 different pages, meaning that you have to make 2 requests to the API, with the exact same values for parameter lastModifiedDateTime, lastModifiedDateTimeCondition and pageSize. The pageNumber-parameter will define what results you will get, marked by the numbers 1-2 and the colors blue and gray in the figure.
If you do not keep these parameters constant (the pageSize is changed), and do the following set of requests:
?lastModifiedDateTime=2020-03-01T00:00:00&lastModifiedDateTimeCondition=>=&pageSize=3&pageNumber=1
?lastModifiedDateTime=2020-03-01T00:00:00&lastModifiedDateTimeCondition=>=&pageSize=5&pageNumber=2
This will result in you getting the following records: First request: Record 1,2,3 Second request: Record 6,7,8,9,10
As you can see the records 4 and 5 will not be returned to you.
New records added while getting pages
Sometimes new records are added to or removed from the database by other uses while you are getting the records using paging. In that scenario the totalCount metadata-property will always change to reflect the new total number of records available for your query. Because of this it is important to always check the value of totalCount for each GET request to retrieve a new page, to be able to calculate the total number of pages needed to get the complete resultset.
Example
You want to get all the customer with status=”Active”, the results should be divided into pages with 10 customers (pageSize=10).
You make the following request to get the first 10 customers. GET/customer?status=Active&pageSize=10&pageNumber=1
As part of the response you get the metadata including the totalCount - property that tells you that the total number of results are 30.
"metadata": {
"totalCount": 30
}
3. This means that you have to repeat the request two more times to get the full result-set. 4. You make the second request to get the next 10 customers. GET/customer?status=Active&pageSize=10&pageNumber=2 5. As part of the response you again get the metadata including the totalCount - property, but this now tells you that the total number of results are 32. Meaning that two new customers have been added or changed status to Active by another user
"metadata": {
"totalCount": 32
}
6. This means that you now have to make a total of 4 requests to get the complete result-set. (10+10+10+2). This shows that your client should always keep track of the total number of results received and the total count of results available to make sure that you always get the complete result-set. The following code-example represents a possible implementation of this.
def get_all_active_customers():
page_size = 10 # The pageSize we want to use
nest_page_number = 1 # The next page to get, initial value = 1
results_recieved = 0 # The number of results we've recieved
total_count = 1 # The total number of results available
#If we've revieved less than the total number of resultes, we make a new loop
while results_recieved < total_count:
response =
request.get('https://integration.visma.net/API/controller/api/v1/customer',
params={
'status': 'Active',
'pageSize': page_size,
'pageNum': next_page_number
},
headers={
'Accept': 'application/json',
'Authorization': 'Bearer' + token,
'ipp-company-id': company_id,
'ipp-application-type': 'Visma-net Financials'
}
| )
if response.status_code == 200:
result = json.loads(response.text) # Decodes the recieved JSON
# {handle the results}
# Increments the number of results recieved by the number of results recieved by this request
results_recieved += result.len
total_count = result[0]['metadata']['totalCount'] # Updates the total_count variable with the current total count of results
next_page_number += 1 # Increments the next page to get by 1
Reference: www.visma.no/erp/api/dokumentasjon/paging
Enforcement of pagination on API endpoints and change of maxPagesize - September release (8.25)
View full article