Important information about paging in Visma.net ERP API

Paging will be enforced on all GET endpoints April 1st 2020

Background

To improve efficiency of integrations it is important that the integration requests only the data needed to perform the desired task from the Visma.net API. This can be achieved by providing filters and or utilizing pagination to reduce the number of results delivered from the API.

Pagination has been supported by Visma.net API for several years and many integrations has already implemented this, however the use of paging has not been mandatory until now. The change is done in order to ensure the efficiency and improve responsiveness of both the API and integrated clients.

If your integration does not support paging, this can result in a breaking change, meaning that your integration will not function as expected after this change takes effect. Therefore it’s important that you read and understand the following information and make the required changes to your integration before the change takes effect on april 1st 2020.

 

Effects on your integration

What is changing?

A range of API end-points will request paging as default. This means that you have to specify a page number and optionally a page size (up to the maximum that an end-point support) when you communicate from your integration towards Visma.net ERP API.

End-points that will request paging that previously accepted the query string arguments “numberToRead” and “skipRecords”, will no longer accept these and they will be disregarded.

A list of which end-points that supports pagination can be found further down in this document. 

We will of course still encourage you to use regular filters in addition to the paging parameters to limit the size of each request. For instance, it is good practice for integrations that need to have all records within a set of filters (or none), to add a filter for “LastModifiedDatetime” in combination with the “LastModifiedDateTimeCondition”. Next time the integration requests the records it should set the value for these filters to > the date of the previous get operation or the datetime value for the last record of the previous get operation.

Consequences 

After April 1st you will experience that end-point by end-point will request paging as part of the communication. For most of the integrations this is a relatively small thing to update, but this depends on how the integration is built. 

Worst case scenario for you as an ISV can be that your customers’ integration will stop working as expected.

If the integration is not taking paging into consideration for instance by not sending the query string arguments for page number and page size, the API will default these to page number 1 and the configured maximum page size. Hence only the first page will be received by the integration.

An integration should not need to know up front what the configured maximum page size is, although we will try to keep our documentation in sync with this. The reason is that this number might change without notification if we find it necessary in order to administer our servers’ load. Instead an integration should ask for the next page if the previous response informs about a total count of records that is still higher than the total amount of records you received since the first request. In every response from a paging-enabled end-point we will aim to inform about the total count of records matching your filters. Some end-point responses have a “metadata” property on every record that has info about the total record count:

Some newer end-points might have wrapped the entire record array in an “envelope” that informs about the count once for the entire response:

But every request conducts a separate database query, so it is possible that this total count changes between page requests. If the end-point does not have a total count member in its response records, you can ask for the next page until the response has no records. For the same reason - and if you have filter on LastModifiedDatetime - you might get some of the same items in a later page request that you already got from a previous one. This is because these items might have been changed by someone else between the integration’s requests, effectively increasing the LastModifiedDatetime value.

If the integration relies on “Skipping”, note that this will no longer be supported by an end-point that requires paging and you should change your code. If nothing is refactored, it will only receive the first page.

Example: How to read from a paginated end-point

Here is an example of a client class with a method to receive pages from the API:

Example of usage:

Affected API endpoints

The following API end-points will from April 1st request pagination in order to be used in an acceptable way. Only the GET-functions will be affected.

Endpoints that supports paging:

/api/v1/cashsale

/api/v1/country

/api/v1/creditNote

/api/v1/customer/{customerCd}/salesorder

/api/v1/customer/{customerCd}/salesorderbasic

/api/v1/customer

/api/v1/customer/{customerNumber}/invoice

/api/v1/customer/{customerNumber}/cashSale

/api/v1/customer/{customerNumber}/document

/api/v1/customerCreditNote

/api/v1/customerCreditWriteOff

/api/v1/customerDebitNote

/api/v1/customerdocument

/api/v1/customerinvoice

/api/v1/customerOverdueCharge

/api/v1/customerPayment

/api/v1/customerpaymentmethod/{customerId}

/api/v1/customerpaymentmethod

/api/v1/customerSalesPrice

/api/v1/deferralCode

/api/v1/employee

/api/v1/generalLedgerBalance

/api/v1/GeneralLedgerTransactions

/api/v1/inventory

/api/v1/inventoryadjustment

/api/v1/inventoryissue

/api/v1/inventoryReceipt

/api/v1/inventoryTransfer

/api/v1/journaltransaction

/api/v1/location/{bAccountId}

/api/v1/location

/api/v1/payment

/api/v1/project

/api/v1/project/tasks

/api/v1/projectbasic

/api/v1/projecttransaction

/api/v1/purchaseorder

/api/v1/purchaseorderbasic

/api/v1/salesorder

/api/v1/salesorderbasic

/api/v1/salesordertype

/api/v1/shipment

/api/v1/subaccount

/api/v1/supplier

/api/v1/supplier/{supplierNumber}/invoice

/api/v1/supplier/{supplierNumber}/document

/api/v1/supplierdocument

/api/v1/supplierInvoice

/api/v1/supplierPayment

/api/v1/vatZone