How Tos /vismanetapi/how-tos section Guides and best practices for integrating with the Visma Net API 2026-01-28T13:55:10+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) ETag and If-Match Headers /vismanetapi/how-tos/etag section Ensuring Data Consistency with ETag and If-Match HTTP Headers 2026-01-28T13:55:10+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/how-tos/date-time-condition-operators section Utilizing DateTime Parameters in Visma Net API Endpoints 2026-01-28T13:55:10+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 the given DateTime. | | `?lastModifiedDateTime=2025-05-25&lastModifiedDateTimeCondition=>=` | Retrieve records after and on the given DateTime | | `?lastModifiedDateTime=2025-05-25&lastModifiedDateTimeCondition=<` | Retrieve records before the given DateTime | | `?lastModifiedDateTime=2025-05-25&lastModifiedDateTimeCondition=<=` | Retrieve records before 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/how-tos/background section How to use “background-api” calls in Visma NET 2026-01-28T13:55:10+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/how-tos/pagination section Visma Net ERP API Pagination Explained 2026-01-28T13:55:10+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 ``` Endpoints for Customer Ledger /vismanetapi/how-tos/customerledgerendpoint section In this article, you will find guidelines on how to use Visma Net API endpoints connected to the Customer Ledger. 2026-01-28T13:55:10+01:00 # Endpoints for Customer Ledger In this article, you will find guidelines on how to use Visma Net API endpoints connected to the Customer Ledger. For more information regarding the endpoints, query parameters, and other endpoints for all areas, please read the [Swagger Documentation](https://finance.visma.net/swaggerui/index.html). Customer /vismanetapi/how-tos/customerledgerendpoint/customer section Common usage example for Customer(ScreenId=AR303000) 2026-01-28T13:55:10+01:00 # Customer Common usage example for Customer(ScreenId=AR303000) URL: `https://api.finance.visma.net/v1/customer` For information about the ERP logic behind Customers, please refer to the [ERP Manual Help: Customers](https://help.content.visma.net/Sweden/SE_EN/online-help/o2c/ar303000-ref.html) ## Methods --- ### GET All Customers URL: `https://api.finance.visma.net/v1/customer` #### Query Parameters - `lastModifiedDateTime=YYYY-MM-DD` As of today Filtering Parameters does not accept certain characters such as W-Z These are the formats for Filtering - `2001-01-01` - `2001-01-01 13:13:13` - `2001-01-01 13:13:13.133` #### Compare Operators for lastModifiedDateTimeCondition - `>` - Greater than - `<` - Less than - `<=` - Less than or equal to - `>=` - Greater than or equal to #### Usage Example This query will return customers updated on 2025-01-14 or later: **GET** `https://api.finance.visma.net/v1/customer?lastModifiedDateTime=2025-01-14&lastModifiedDateTimeCondition=>=` --- ### POST Customer URL: `https://api.finance.visma.net/v1/customer` This example shows the minimum fields you should send to be able to post a new Customer, if you are using automatic numbering you can omit the “number” field. #### JSON Request body ```json { "number": { "value": "10000" }, "name": { "value": "NewCustomer" }, "overrideWithClassValues": true, "customerClassId": { "value": "1" }, "mainAddress": { "value": { "addressLine1": { "value": "TestRoad 13" }, "postalCode": { "value": "0101" }, "countryId": { "value": "NO" } } } } ``` If sent successfully, the API will return: ![Created](201created2.png) --- ### POST action/createDunningLetter URL: `https://api.finance.visma.net/v1/customer/{customerNumber}/action/createDunningLetter` #### JSON Request body ```json { "dunningLetterDate": "2025-01-21T09:39:48.538Z", "levelFrom": 1, "levelTo": 2 } ``` If successful the API will return a message as below: ![Created](201created2.png) Response body: ```json { "actionId": "2ddece9b-a89b-4f5a-a251-2cf14837bb2d", "actionResult": "Done" } ``` --- ### PUT Customer URL: PUT `https://api.finance.visma.net/v1/customer/{customerNumber}` When using PUT, you only send the fields you want to update. In the below example, we update the mainAddress of the customer: URL: `https://api.finance.visma.net/v1/customer/{customerNumber}` #### JSON Request body ```json { "mainAddress": { "value": { "addressLine1": { "value": "TestRoad 50" }, "postalCode": { "value": "0101" }, "countryId": { "value": "NO" } } } } ``` If successful the API will return a message as below: ![No Content](nocontent.png) --- Customer Credit Note /vismanetapi/how-tos/customerledgerendpoint/customercreditnote section Common usage example for Customer Credit Note (ScreenId=AR301000) 2026-01-28T13:55:10+01:00 # Customer Credit Note Common usage example for Customer Credit Note (ScreenId=AR301000) URL: `https://api.finance.visma.net/v1/CustomerCreditNote` For information about the ERP logic behind Customer Credit Note, please refer to the [ERP Manual Help: Sales invoices of type Credit note](https://help.content.visma.net/Sweden/SE_EN/online-help/o2c/ar301000-ref.html) ## Methods --- ### All Customer Credit Notes URL: `https://api.finance.visma.net/v1/CustomerCreditNote` #### Query Parameters - financialPeriod=YYYYMM Lets you define what financialPeriod to include in the response - status=string Limits response to CreditNotes with a status - expandAttachments=boolean Lets you decide if you want attachments to be expanded or not. - expandTaxDetails=boolean Lets you decide if you want tax detail lines to be expanded or not. #### Usage Example This will return Customer CreditNotes in the financial period 01-2020 that have the status “balanced”, and will not expand attachments or tax detail lines. **GET** `https://api.finance.visma.net/v1/customerCreditNote?financialPeriod=202001&status=balanced&expandAttachments=false&expandTaxDetails=false` --- ### POST CustomerCreditNote URL: `https://api.finance.visma.net/v1/CustomerCreditNote` This example shows the minimum fields you should send to be able to post a new Customer Credit Note, if you are using automatic numbering you can omit the “referenceNumber” field. #### JSON Request body ```json { "currencyId": { "value": "NOK" }, "externalReference": { "value": "ExRef" }, "lines": [ { "operation": "Insert", "inventoryNumber": { "value": "A" }, "quantity": { "value": 1 }, "unitPriceInCurrency": { "value": 1 } } ], "customerNumber": { "value": "10000" }, "referenceNumber": { "value": "25698" }, "documentDate": { "value": "2025-11-21" }, "postPeriod": { "value": "112025" }, "financialPeriod": { "value": "202511" } } ``` If sent successfully, the API will return: ![Created](201created5.png) --- ### PUT CustomerCreditNote URL: `https://api.finance.visma.net/v1/CustomerCreditNote/{creditNoteNumber}` When using PUT, you only send the fields you want to update. In the below example, we update the first line of the Credit Note: URL: PUT `https://api.finance.visma.net/v1/CustomerCreditNote/25698` #### JSON Request body ```json { "lines": [ { "operation": "Update", "lineNumber": { "value": 1 }, "inventoryNumber": { "value": "6" }, "quantity": { "value": 1 }, "unitPriceInCurrency": { "value": 1 } } ] } ``` If sent successfully, the API will return: ![No Content](nocontent2.png) --- Customer Debit Note /vismanetapi/how-tos/customerledgerendpoint/customerdebitnote section Common usage example for Customer Debit Note (ScreenId=AR301000) 2026-01-28T13:55:10+01:00 # Customer Debit Note Common usage example for Customer Debit Note (ScreenId=AR301000) URL: `https://api.finance.visma.net/v1/CustomerDebittNote` For information about the ERP logic behind Customer Debit Note, please refer to the [ERP Manual Help: Sales invoices of type Debit note](https://help.content.visma.net/Sweden/SE_EN/online-help/o2c/ar301000-ref.html) ## Methods --- ### All Customer Debit Notes URL: `https://api.finance.visma.net/v1/CustomerDebitNote` #### Query Parameters - Project=String Will limit response to documents with the specified project #### Usage Example This will return Customer Debit Notes with projectID 20. **GET** `https://api.finance.visma.net/v1/customerDebitNote?project=20` --- ### POST CustomerDebitNote URL: `https://api.finance.visma.net/v1/CustomerDebitNote` This example shows the minimum fields you should send to be able to post a new Customer Debit Note, if you are using automatic numbering you can omit the “referenceNumber” field. #### JSON Request body ```json { "lines": [ { "operation": "Insert", "description": { "value": "Test" }, "quantity": { "value": 2 }, "unitPriceInCurrency": { "value": 2 }, "uom": { "value": "STK" } } ], "customerNumber": { "value": "10000" }, "referenceNumber": { "value": "000050" }, "documentDate": { "value": "2025-01-16" }, "postPeriod": { "value": "012025" }, "financialPeriod": { "value": "202501" }, "invoiceText": { "value": "DebitNote" } } ``` If sent successfully, the API will return: ![Created](201created4.png) --- ### PUT CustomerDebitNote URL: `https://api.finance.visma.net/v1/CustomerDebitNote/{debitNoteNumber}` When using PUT, you only send the fields you want to update. In the below example, we update the first line of the Debit Note: URL: PUT `https://api.finance.visma.net/v1/CustomerDebitNote/000050` #### JSON Request body ```json { "lines": [ { "operation": "Insert", "lineNumber": { "value": 1 }, "inventoryNumber": { "value": "6" }, "quantity": { "value": 1 }, "unitPriceInCurrency": { "value": 1 } } ] } ``` If sent successfully, the API will return: ![No Content](nocontent3.png) Customer Invoice /vismanetapi/how-tos/customerledgerendpoint/customerinvoice section Common usage example for Customer Invoice (ScreenId=AR301000) 2026-01-28T13:55:10+01:00 # Customer Invoice Common usage example for Customer Invoice (ScreenId=AR301000) URL: `https://api.finance.visma.net/v1/CustomerInvoice` For information about the ERP logic behind Customer Invoice, please refer to the [ERP Manual Help: Sales invoices of type Invoice](https://help.content.visma.net/Sweden/SE_EN/online-help/o2c/ar301000-ref.html) ## Methods --- ### All Customer Invoice URL: `https://api.finance.visma.net/v1/CustomerInvoice` #### Query Parameters - `lastModifiedDateTime=YYYY-MM-DD` As of today Filtering Parameters does not accept certain characters such as W-Z These are the formats for Filtering - `2001-01-01` - `2001-01-01 13:13:13` - `2001-01-01 13:13:13.133` #### Compare Operators for lastModifiedDateTimeCondition - `>` - Greater than - `<` - Less than - `<=` - Less than or equal to - `>=` - Greater than or equal to #### Usage Example This query will return suppliers updated on 2025-01-14 or later: **GET** `https://api.finance.visma.net/v1/CustomerInvoice?lastModifiedDateTime=2025-01-14&lastModifiedDateTimeCondition=>=` --- ### POST Customer Invoice URL: `https://api.finance.visma.net/v1/CustomerInvoice` This example shows the minimum fields you should send to be able to post a new Customer Invoice, if you are using automatic numbering you can omit the “referenceNumber” field. #### JSON Request body ```json { "invoiceLines": [ { "operation": "Insert", "inventoryNumber": { "value": "222" }, "quantity": { "value": 500 }, "uom": { "value": "STK" } } ], "referenceNumber": { "value": "156589" }, "customerNumber": { "value": "10000" }, "documentDate": { "value": "2025-01-27" }, "invoiceText": { "value": "Payment for potatoes" } } ``` If sent successfully, the API will return: ![Created](201created3.png) --- ### PUT CustomerInvoice URL: `https://api.finance.visma.net/v1/CustomerInvoice/{InvoiceNumber}` When using PUT, you only send the fields you want to update. In the below example, we update the first line of the Invoice: URL: PUT `https://api.finance.visma.net/v1/CustomerInvoice/003547` #### JSON Request body ```json { "invoiceLines": [ { "operation": "Insert", "lineNumber": { "value": 1 }, "inventoryNumber": { "value": "6" }, "quantity": { "value": 1 }, "unitPriceInCurrency": { "value": 1 } } ] } ``` If sent successfully, the API will return: ![No Content](nocontent2.png) Endpoints for Supplier Ledger /vismanetapi/how-tos/supplierledgerendpoint section In this article, you will find guidelines on how to use Visma Net API endpoints connected to the Supplier Ledger. 2026-01-28T13:55:10+01:00 # Endpoints for Supplier Ledger In this article, you will find guidelines on how to use Visma Net API endpoints connected to the Supplier Ledger. For more information regarding the endpoints, query parameters, and other endpoints for all areas, please read the [Swagger Documentation](https://finance.visma.net/swaggerui/index.html). Supplier /vismanetapi/how-tos/supplierledgerendpoint/supplier section Common usage example for Supplier(ScreenId=AP303000) 2026-01-28T13:55:10+01:00 # Supplier Common usage example for Supplier(ScreenId=AP303000) URL: `https://api.finance.visma.net/v1/supplier` For information about the ERP logic behind Suppliers, please refer to the [ERP Manual Help: Suppliers](https://help.content.visma.net/Sweden/SE_EN/online-help/p2p/AP/AP303000-ref.html) ## Methods --- ### GET All Suppliers URL: `https://api.finance.visma.net/v1/supplier` #### Query Parameters - `lastModifiedDateTime=YYYY-MM-DD` As of today Filtering Parameters does not accept certain characters such as W-Z These are the formats for Filtering - `2001-01-01` - `2001-01-01 13:13:13` - `2001-01-01 13:13:13.133` #### Compare Operators for lastModifiedDateTimeCondition - `>` - Greater than - `<` - Less than - `<=` - Less than or equal to - `>=` - Greater than or equal to #### Usage Example This query will return suppliers updated on 2025-01-14 or later: **GET** `https://api.finance.visma.net/v1/supplier?lastModifiedDateTime=2025-01-14&lastModifiedDateTimeCondition=>=` --- ### POST Supplier URL: `https://api.finance.visma.net/v1/supplier` This example shows the minimum fields you should send to be able to post a new Supplier, if you are using automatic numbering you can omit the “number” field. #### JSON Request body ```json { "number": { "value": "50002" }, "name": { "value": "NewSupplier" }, "mainAddress": { "addressId": 3001, "addressLine1": "Testroad 5", "postalCode": "0110", "city": "OSLO", "country": { "id": "NO", "name": "NORGE" }, "county": { "id": "0301", "name": "OSLO" } }, "supplierClassId": { "value": "1" } } ``` If sent successfully, the API will return: ![Created](201created2.png) --- Supplier Invoice /vismanetapi/how-tos/supplierledgerendpoint/supplierinvoice section Common usage example for Supplier Invoice(ScreenId=AP301000) 2026-01-28T13:55:10+01:00 # Supplier Invoice Common usage example for Supplier Invoice(ScreenId=AP301000) URL: `https://api.finance.visma.net/v1/supplierInvoice` For information about the ERP logic behind Supplier Invoices, please refer to the [ERP Manual Help: Purchase invoices](https://help.content.visma.net/Sweden/SE_EN/online-help/p2p/AP/AP301000-ref.html) ## Methods --- ### GET All Supplier Invoices URL: `https://api.finance.visma.net/v1/supplierInvoice` #### Query Parameters - Project=String Will limit response to documents with the specified project #### Usage Example This will return Supplier Invoices with projectID 20. **GET** `https://api.finance.visma.net/v1/supplierInvoice?project=20` --- ### POST SupplierInvoice URL: `https://api.finance.visma.net/v1/supplierInvoice` This example shows the minimum fields you should send to be able to post a new Supplier Invoice, if you are using automatic numbering you can omit the “referenceNumber” field. #### JSON Request body ```json { "date": { "value": "2025-11-08T00:00:00" }, "documentType": { "value": "Invoice" }, "referenceNumber": { "value": "000357" }, "invoiceLines": [ { "inventoryNumber": { "value": "test*test" }, "lineNumber": { "value": "1" }, "operation": "Insert", "projectId": { "value": "X" }, "quantity": { "value": 1 }, "subaccount": [ { "segmentId": 1, "segmentValue": "00" } ], "unitCostInCurrency": { "value": "1.60" }, "vatCodeId": { "value": "1" } } ], "paymentRefNo": { "value": "test" }, "postPeriod": { "value": "112025" }, "supplierNumber": { "value": "50000" }, "supplierReference": { "value": "test" } } ``` If sent successfully, the API will return: ![Created](201created3.png) --- ### PUT SupplierInvoice URL: `https://api.finance.visma.net/v1/supplierInvoice/{invoiceNumber}` When using PUT, you only send the fields you want to update. In the below example, we update the first line of the invoice: URL PUT `https://api.finance.visma.net/v1/supplierInvoice/000050`' #### JSON Request body ```json { "invoiceLines": [ { "operation": "Update", "lineNumber": { "value": 1 }, "inventoryNumber": { "value": "6" }, "quantity": { "value": 1 } } ] } ``` If successful, the API will return: ![No Content](nocontent2.png) --- Purchase Order /vismanetapi/how-tos/supplierledgerendpoint/purchaseorder section Common usage example for Endpoint(ScreenId=PO301000) 2026-01-28T13:55:10+01:00 # Purchase Order Common usage example for Endpoint(ScreenId=PO301000) URL: `https://api.finance.visma.net/v1/PurchaseOrder` For information about the ERP logic behind Purchase Orders, please refer to the [ERP Manual Help: Purchase orders](https://help.content.visma.net/Sweden/SE_EN/online-help/o2c/PO/PO301000-ref.html) ## Methods --- ### GET ALL Purchase Orders URL: `https://api.finance.visma.net/v1/PurchaseOrder` #### Query Parameters ##### Supplier=string Lets you search for Purchase Orders registered to one supplier ##### orderStatus=string Lets you define what orderStatuses to return, these are the Statuses of Purchase Order: - On hold - The purchase order is a draft and can be edited manually. - Open - The order was processed in accordance but has not been completed yet. - Pending approval - The purchase order has not been approved by all the assigned persons. - Rejected - The order was rejected by one of the persons assigned to approve it. - Pending printing - Printing is required for the document but has not been performed yet. - Pending e-mail - E-mailing is required for this document, but it has not been performed yet. - Closed - All the ordered goods were received. - Cancelled - The order was cancelled through the “ Cancel order” action - An order with this - status cannot be edited, and purchase receipts cannot be based on it. #### Usage Example This will return Purchase Orders registered on supplier “50000” that are in status OPEN. **GET** `https://api.finance.visma.net/v1/purchaseorder?Supplier=50000&status=open` --- ### POST Purchase Order URL: `https://api.finance.visma.net/v1/purchaseorder` This example shows the minimum fields you should send to be able to post a new Purchase Order, if you are using automatic numbering you can omit the “referenceNumber” field. #### JSON Request body ```json { "orderType": { "value": "RegularOrder" }, "date": { "value": "2019-12-27T09:46:11.202Z" }, "supplier": { "value": "50000" }, "lines": [ { "operation": "Insert", "inventory": { "value": "teststock" }, "lineType": { "value": "GoodsForInventory" }, "warehouse": { "value": "2" }, "uom": { "value": "PALL" }, "orderQty": { "value": 2 }, "unitCost": { "value": 2000 } } ] } ``` If sent successfully, the API will return: ![Created](201created4.png) --- ### PUT Purchase Order URL: `https://api.finance.visma.net/v1/purchaseorder/{purchaseOrder}` When using PUT, you only send the fields you want to update. In the below example, we update the first line of the Credit Note: URL PUT `https://api.finance.visma.net/v1/supplierInvoice/000050`' #### JSON Request body ```json { "lines": [ { "operation": "Update", "lineNumber": { "value": 1 }, "inventory": { "value": "6" }, "orderQty": { "value": 1 } } ] } ``` If successful, the API will return: ![No Content](nocontent3.png) --- Supplier Payment /vismanetapi/how-tos/supplierledgerendpoint/supplierpayment section Common usage example for Endpoint(ScreenId=AP302000) 2026-01-28T13:55:10+01:00 # Supplier Payment Common usage example for Endpoint(ScreenId=AP302000) URL: `https://api.finance.visma.net/v1/supplierPayment` For information about the ERP logic behind Supplier Payment, please refer to the [ERP Manual Help: Supplier payments](https://help.content.visma.net/Sweden/SE_EN/online-help/p2p/AP/AP302000-ref.html) ## Methods --- ### GET All Supplier Payments URL: `https://api.finance.visma.net/v1/supplierPayment` #### Query Parameters - SupplierId=String This will limit the response to the provided SupplierId #### Usage Example This will return Supplier Payments registered on supplier “50000” **GET** `https://api.finance.visma.net/v1/supplierPayment?supplier=50000` --- Attachment /vismanetapi/how-tos/attachment section How to post and fetch attachments 2026-01-28T13:55:10+01:00 # Attachment How to post and fetch attachments ## How to POST an Attachment via Visma Net API in C#? > [!Note] > Please read more about the attachment-specific endpoints at [Documentation/Swagger](https://docs.vismasoftware.no/vismanetapi/#documentationswagger) ### WebClient Class ```csharp public void postAttachment(string[] files, string , string token, string companyId) { using (WebClient client = new WebClient()) { client.Headers.Add("ipp-company-id", ""); client.Headers.Add("ipp-application-type", "Visma.net Financials"); client.Headers.Add("Authorization", "bearer"); for (int i = 0; i < files.Length; i++) // Multiple { byte[] responseArray = client.UploadFile( @"https://api.finance.visma.net/v1///Attachment", "POST", files[i] ); } } } ``` ### HttpClient Class ```csharp public void postAttachmentHttpClient() { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("ipp-application-type", "Visma.net Financials"); client.DefaultRequestHeaders.Add("ipp-company-id", ""); client.DefaultRequestHeaders.Add("Authorization", "Bearer "); HttpResponseMessage response; var content = new MultipartFormDataContent(); var path = Path.Combine(@""); string fileName = Path.GetFileName(path); FileStream fs = File.OpenRead(path); var sc = new StreamContent(fs); sc.Headers.Add("Content-Type", "application/octet-stream"); sc.Headers.Add("Content-Disposition","form-data; name=\"file\"; filename=\"" + Path.GetFileName(path) + "\""); content.Add(sc, "file", fileName); response = client.PostAsync(@"https://api.finance.visma.net/v1///Attachment", content).Result; } } ``` > [!Important] > The sample code is provided “AS IS” and any express or implied warranties, including the implied warranties of merchantability and fitness for a particular purpose, are disclaimed. In no event shall Visma or contributors be liable for any direct, indirect, incidental, special, exemplary or consequential damages. ## How to fetch attachment **Step 1.** Fetch the attachmentid from the document, for example GET ![GetInvoice](getInvoice.png) **Step 2.** Fetch the Base64 using the attachmentid from step one in the attachment endpoint. For example: GET ![GetAttachment](getAttachment.png) **Step 3.** Once you have fetched the Base64, you should be able to decode it to a file