How Tos /vismanetapi/setting-up-your-integration/how-tos section Guides and best practices for integrating with the Visma Net API 2025-11-06T14:11:33+01:00 # How Tos Guides and best practices for integrating with the Visma Net API In this section you will learn more about Visma Net API. It includes important techniques and best practises for secure and effective integration. - [ETag and If-Match Headers](etag.md) - [DateTimeCondition & Operators](date-time-condition-operators.md) - [Background API calls](background.md) - [Pagination](pagination.md) ETag and If-Match Headers /vismanetapi/setting-up-your-integration/how-tos/etag section Ensuring Data Consistency with ETag and If-Match HTTP Headers 2025-11-06T09:47:29+01:00 # ETag and If-Match Headers Ensuring Data Consistency with ETag and If-Match HTTP Headers ## Overview In modern web applications, ensuring data consistency and preventing conflicts is essential, especially when multiple clients attempt to update the same resource concurrently. The ETag and If-Match HTTP headers offer a solution for these challenges. Here's how they work together to maintain data integrity. ## ETag Response Header An ETag (Entity Tag) is a unique identifier that the server assigns to a specific version of a resource. It is included in the response header when a client requests the resource. This identifier helps clients in managing cache and detecting resource changes. - **Usage in API**: When a client requests a resource, the server responds with the ETag value in the response header and as part of the response DTO (with the field name: "**Timestamp**"). - **Pagination Note**: During paginated responses, the ETag value isn't included in the response header but is available within the response DTO (Field name: "**Timestamp**"). ## If-Match Request Header (Optional) The If-Match HTTP header is used by clients to signal that they wish to update a resource only if its current version matches a specific ETag. This mechanism prevents resource conflicts when multiple clients try to update the same resource simultaneously. Refer to Also: [Lost Update Problem](https://www.w3.org/1999/04/Editing/#3.1), [If-Match](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/If-Match), [HTTP conditional requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Conditional_requests). - **Conflict Prevention**: If the ETag stored on the server doesn't match the client's If-Match header, the server responds with a 412 Precondition Failed status code. - **Usage in API**: Currently, the "If-Match" header is optional and can only be used with certain PUT & POST action endpoints shared in detail in the following section below. ## Example **1. GET**: .../v1/supplier/xxxxx **Response headers**: ETag ![ETag](etag.jpg) **Response body**: timeStamp ![TimeStamp](timestamp.jpg) **2. PUT**: .../v1/supplier/xxxxx **Request headers**: If-Match ![Header](header.jpg) This request will succeed in updating the resource only if the resource's current "ETag" is "AAAAAE0YIiI=". **A. In case of success**, the server returns "204 - No content" together with the new ETag value in the response headers. ![ETag2](etag2.jpg) **B. In case of failure**, the server returns "412 - Precondition Failed". ![Message](message2.jpg) ## Advantages of using ETag and If-Match - **Optimistic concurrency control**: By using If-Match headers, clients can ensure that updates to resources are made safely without unwanted overwrites. - **Data Integrity**: Helps maintain data consistency by validating that resource updates are based on the most current data. ## API Endpoints with ETag and If-Match Header Support ### Endpoints & Operations Supporting "ETag" Response Header GET, PUT & POST operations on the following endpoints include an "etag" in the response header: - Account - Budget - CashSale - CashTransaction - Contact - Customer - CustomerCreditWriteOff - CustomerDebitNote - CustomerInvoice - CustomerOverdueCharge - CustomerPayment - Dimension - Employee - ExpenseClaim - JournalTransaction - PurchaseOrder - PurchaseOrderBasic - PurchaseReceipt - PurchaseReceiptBasic - Shipment - Subaccount - Supplier - SupplierInvoice - SupplierLocation - SupplierPayment - Timecard Note: "TimeStamp" field can also be checked via the DTOs where it's exposed. ### Endpoints & Operations Supporting "If-Match" Request Header - PUT Account - PUT Budget - PUT CashTransaction - PUT CashSale - PUT Contact - PUT Customer - PUT CustomerDebitNote - PUT CustomerInvoice - PUT CustomerOverdueCharge - PUT CustomerPayment - PUT Dimension - PUT Employee - PUT ExpenseClaim - PUT JournalTransaction - PUT PurchaseOrder - PUT PurchaseOrderBasic - PUT PurchaseReceipt - PUT PurchaseReceiptBasic - PUT Shipment - PUT Subaccount - PUT Supplier - PUT SupplierInvoice - PUT SupplierLocation - PUT SupplierPayment - PUT Timecard **If the endpoint is asynchronous**, meaning that if it immediately returns a "202-Accepted" HTTP response and starts the actual job in the background, such as "Action"-based operations. (Endpoint URL: …/action/…) If-Match is supported in the following actions only with "**erp-api-background** usage": - POST CustomerDebitNote action/Release - POST CustomerDebitNote action/sendToAutoInvoice - POST CustomerOverdueCharge action/release - POST CustomerPayment action/Release - POST CustomerPayment action/Void - POST SupplierPayment action/Release - POST SupplierInvoice action/Release - POST SupplierInvoice action/Prebook - POST SupplierInvoice action/voidinvoice - POST SupplierInvoice action/sendtoapproval DateTimeCondition & Operators /vismanetapi/setting-up-your-integration/how-tos/date-time-condition-operators section Utilizing DateTime Parameters in Visma Net API Endpoints 2025-11-06T14:11:33+01:00 # DateTimeCondition & Operators Utilizing DateTime Parameters in Visma Net API Endpoints ## Overview In this article, you can find guidelines on utilizing Visma Net API Endpoints using DateTime parameters, as well as their associated condition and operators. For more information regarding the endpoints, query parameters and other endpoints for all areas, please read the documentation found here: [Swagger - Visma Net Documentation](https://finance.visma.net/swaggerui/index.html) ## lastModifiedDateTimeCondition=Operator Supported comparative operators for LastModifiedDateTime Conditions on filtering: | Operator | Description | |-----------|-------------------------| | `>` | Greater than | | `<` | Less than | | `<=` | Less than or equal to | | `>=` | Greater than or equal to| ## Explanation | Query | Description | |----------------------------------------------------------------------|------------------------------------------------| | `?lastModifiedDateTime=2025-05-25&lastModifiedDateTimeCondition=>` | Retrieve records after and on the given DateTime | | `?lastModifiedDateTime=2025-05-25&lastModifiedDateTimeCondition=<=` | Retrieve records before and on the given DateTime| | `?lastModifiedDateTime=2025-05-25&lastModifiedDateTimeCondition=<=` | Retrieve records before and on the given DateTime| | `?lastModifiedDateTime=2025-05-25&lastModifiedDateTimeCondition=>=` | Retrieve records after and on the given DateTime | ## Usage example This query will return customers updated on 2025-05-25 or later. ```plaintext GET https://api.finance.visma.net/v1/customer ?lastModifiedDateTime=2025-05-25 &lastModifiedDateTimeCondition=>= ``` (Lines are separated for readability) ## The operators are used the same for createdDateTimeCondition=**Operator** dunningLetterDateTimeCondition=**Operator** Background API calls /vismanetapi/setting-up-your-integration/how-tos/background section How to use “background-api” calls in Visma NET 2025-11-06T14:11:33+01:00 # Background API calls How to use “background-api” calls in Visma NET ## Overview A “background-api” request is a regular request, but with an extra header “erp-api-background” with the value “subscription”, “subscription:``” or “none” (without quotes). The API request will then be saved into a queue and responded with a jobId and status 202. The actual work will be handled in the background by the first server with free capacity. There will be no notification when the call is done executing. With the value “subscription”, a webhook notification will be sent to the webhook subscriber that is set up in Developer Portal for the “Visma net” application event named “BACKGROUND_API_RESPONSE”. The `` part is optional. It supports name/value pairs in the format ``=``,..,``=``. When specified, the keys will end up as custom headers in the webhook notification with the corresponding values. Here you can typically specify your own reference ids to be able to recognize custom state for the operation in your webhook listener. One can at any time the next 24 hours GET /api/v1/background/{id} to poll the status of a background-api operation. Current usages of the erp-api-background header with a url as a value, will still work for a while, but you are advised to register these as webhook subscriptions in Developer Portal and refactor client code accordingly, since we plan to end the current mechanism. Recommended for: API requests taking more than 4 minutes. All API requests that spend more than 4 minutes can be refactored into being “background-api” calls. **Note: background-api using this header mechanism, works only for v1 and v2 api endpoints currently.** Pagination /vismanetapi/setting-up-your-integration/how-tos/pagination section Visma Net ERP API Pagination Explained 2025-11-06T14:11:33+01:00 # Pagination Visma Net ERP API Pagination Explained ## About Paging When retrieving lists of data from API endpoints, it is most efficient for both the client and server to divide the results into portions rather than retrieving all the data at once. The Visma Net API supports this through 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 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 retrieve all these. To limit the number of customers received, you can divide this into pages that contain up to 100 customers (**pageSize=100**). To get the complete list, you then have to make 4 requests to the Customer endpoint: | Request | Result | |------------------------------------------|--------------------------------------------------| | GET /customer?pageSize=100&pageNumber=1 | Returns the first 100 customers (1-100) | | GET /customer?pageSize=100&pageNumber=2 | Returns the second page of 100 customers (101-200) | | GET /customer?pageSize=100&pageNumber=3 | Returns the third page of 100 customers (201-300) | | GET /customer?pageSize=100&pageNumber=4 | Returns the last page of remaining customers (301-350) | Paging is implemented on all GET endpoints that return lists in the Visma Net API. It is mandatory to use the parameters **pageSize** and **pageNumber** in all requests to endpoints that support this. ## Paging in Visma Net API For all endpoints that return lists paging is implemented by providing two query parameters: **pageSize** and **pageNumber**. For all endpoints these parameters are documented in the [Visma Net Swagger documentation](https://finance.visma.net/swaggerui). 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. ## Paging in Sales Order Service API Paging is also implemented in the Sales Orders API using the parameters **pageSize** and **pageIndex** (instead of **pageNumber**). More information can be found in the [Sales Order Swagger documentation](https://salesorder.visma.net/swagger/). ## Default Parameter Values | Parameter | Default value (if not provided) | |-----------|--------------------------------------------------------| | pageNumber| 1 | | pageSize | Can vary by endpoint, and 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 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: ```c# "metadata": { "totalCount": 450, "maxPageSize": 1000 } ``` ### Metadata: 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. ### Metadata: 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 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. ![Pagination](pagination.jpg) 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). 1 You make the following request to get the first 10 customers. GET/customer?status=Active&pageSize=10&pageNumber=1 2 As part of the response you get the metadata including the totalCount - property that tells you that the total number of results are 30. ```c# "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 ```c# "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: ```python 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 ```