REST API guide

From Zero to First API Call

This guide will walk you through the steps needed to make your first API call. The goal is to retrieve the list of customers in your Visma Severa account using an API endpoint dedicated for that purpose.

We recommend you read this guide from start to finish and then freely navigate the rest of the documentation.

To make an API call, you’ll have to

  1. enable REST API for your account
  2. create a new client id and secret
  3. obtain an API access token
  4. discover the desired endpoint
  5. make the call to the endpoint passing in the obtained access token

Enable Visma Severa REST API for your account

To be able to create client credentials, login as the administrator, and enable the Visma Severa REST API upgrade. This can be done from Upgrades under Settings.

After enabling the upgrade, you should be able to see REST API menu section under Settings.

Logging in as administrator and enabling Visma Severa upgrade makes REST API menu section visible.

Now you’re ready to create client ids and secrets.

Create client id and secret in Visma Severa

To create client id and secret, while logged in as the administrator in Visma Severa, navigate to REST API under Settings.

If the REST API menu is not visible, either you don’t have the Visma Severa REST API upgrade enabled or you’re not logged in as the administrator.

Client credentials are created from REST API under Settings.

Click Create client credentials and fill in the target system and the purpose of the integration.

If you plan to use a 3rd party vendor to implement the integration, we recommend filling in the contact details of the partner in the Integration partner section. This information helps local Visma Severa support during troubleshooting.

New client credentials are created by filling the target system, the purpose of integration and optional information about an integration partner.

In the Select API scopes dialog, select the permissions you wish to grant to this set of credentials. We are interested in listing all customers, so add the customers:read scope. See Scopes for a full list of available scopes.

API scopes control what operations a set of client credentials is allowed to perform.

After you hit Apply to close permissions dialog and Save to finish creating new client credentials, Visma Severa generates a new client id and secret. We use them later to obtain an API access token.

After creating new client credentials, you’ll receive the client id and client secret.

It’s recommended that you create dedicated credentials for each 3rd party application instead of sharing the same credentials with all applications.

Environment URL

Now that you’ve created the client id and client secret, you’re ready to make your first API call. For that, you need to know where to send your requests. The URL for the current production version of Visma Severa REST API is:

https://api.severa.visma.com/rest-api/v0.2

Get API access token using POST /token

Visma Severa REST API uses OAuth 2.0 bearer tokens to authenticate API calls. You’ll receive an access token upon a successful login, and the token is sent in the HTTP header of every subsequent call.

sequenceDiagram participant U as Application participant t as /token participant c as /customers U->>+t: POST /token t->>-U: 🔑 Note over U, t: Access token U->>+c: GET /customers
Authorization: Bearer 🔑 Note over U, c: Received access token is set in Authorization-header c->>-U: .

The received access token from POST /token is sent in the Authorization HTTP header of a subsequent call.

You can obtain an access token by calling POST /token and passing in the client id, client secret and requested permission scopes. If passing multiple scopes, the scope names are separated by the space character.

We recommend requesting minimal set of scopes needed for planned operations, even if the client credentials would have access to a greater set of permissions.

In response, you’ll receive authentication information along with the user profile. The access_token field in the response holds the API access token.

Example of obtaining an access token
Request:
POST /token
Content-type: application/json

{
  "client_Id": "DemoCompany(tm)_i1gNXpV6i6YlVHj3HJ.ap...",
  "client_Secret": "d0b3e9d0-a20e-7c0f-a887-224659121...",
  "scope": "customers:read"
}
Response:
{
  ...
  "access_token": "haTWcVRe456kbBrNPYJtO8FzrIBKUvz...",
  ...
}

The access token is now authorized to perform operations with the requested permission scope. The token is valid for 1 hour. When the token is about to expire, you can refresh it using a separate call.

For all subsequent calls, you’ll pass the client id and the received access token in the HTTP header of each request. The client id is set in client_id header, and the access token is set in Authorization header with type Bearer. For example:

GET /customers
client_id: DemoCompany(tm)_i1gNXpV6i6YlVHj3HJ.apps.vi...
Authorization: Bearer haTWcVRe456kbBrNPYJtO8FzrIBKUvz...

You now have an access token, and it’s time to find the right endpoint. The endpoints in the Visma Severa REST API can be grouped by topic:

  • customers
  • users
  • projects
  • work hours
  • project fees
  • travel expenses
  • invoices

A detailed description of the endpoints is available in API Specification.

The API Specification includes the customers family of endpoints along with accepted parameters and return values.

The GET /customers endpoint returns a list of customers in your Visma Severa account. That’s the endpoint you’re going to use.

Make API call by passing access token

Now, you have an access token, and you’ve identified the endpoint you want to use. You’re ready to make the call.

Make a GET request to /customers endpoint and pass the client id and secret in the HTTP header. The client id is set in client_id HTTP header and the access token in Authorization HTTP header using the type Bearer.

GET /customers
client_id: DemoCompany(tm)_i1gNXpV6i6YlVHj3HJ.apps.vi...
Authorization: Bearer haTWcVRe456kbBrNPYJtO8FzrIBKUvz...
sequenceDiagram participant U as Application participant c as /customers U->>+c: GET /customers
client_id: i1gNXpV6...
Authorization: Bearer haTWcVRe... Note over U, c: Client id and received access token
is set in HTTP header c->>-U: .

A call to GET /customers authenticates by sending the client id and client secret in the HTTP headers.

As a response, you’ll receive a list of customers in your Visma Severa account.

Example response of GET /customers
Content-type: application/json

[
    {
        "guid": "14523e93-1096-3fc2-7256-165b9064f4c1",
        "name": "Customer A",
        "number": 1199,
        "isActive": true,
        "isInternal": false,
        "notes": null,
        "email": null,
        ...
    },
    ...
]

At this point, you’ve completed the task we set out to do - to get a list of customers in your Visma Severa account. You performed all steps needed to make the call happen: creating a client secret, obtaining an access token and finding the right API.

Ready to dive into rest of documentation

Now that you’ve got the basics covered, you’re ready to freely navigate the rest of the documentation. You might be interested in common Use Cases, read more about the Concepts used in the API, or dive into the API Specification for a detailed list of the available endpoints and allowed parameters.

Uses cases

Import work hours

Importing work hours from a 3rd party application into Visma Severa is a common use case. This can be, for example, to transfer hours from a time tracking system to Visma Severa for invoicing.

Model of work hours and projects

A work hour is associated with user, project phase and work type. Project phase, in turn, is associated with a project.

flowchart TD WH[Work Hour] U[User] P[Project] PP[Project Phase] WT[Work Type] WH --- U WH --- PP PP --- P WH --- WT

A work hour is related to user, project phase and work type.

Determine values for user, project phase and work type

In order to insert a work hour, the existing user, project phase and work type must be known. Visma Severa uses "guid"s to reference other objects.

User

Users can be fetched from the GET /users endpoint. Email address is a good candidate when matching users from Visma Severa to users in the 3rd party application.

Ideally, you’d synchronize user data completely into the 3rd party application before starting to import work hours. This avoids re-querying the API for user data for each imported hour. See Synchronizing data.

Project phase

Projects in Visma Severa consist of project phases, and work hours are targeted specifically to a project phase.

There are a couple of options to fetch project phases. One way is to get a list of projects using GET /projects, and then get the phases of one particular project using GET /projects/{guid}/phaseswithhierarchy

It might not be possible to automatically match a project name in the 3rd party application with a project phase name in Visma Severa. In such a case, a manual mapping configuration in the 3rd party application is one option. In that approach, the "guid" of a project phase is saved in the 3rd party application, and that value is then used when importing the hours to Visma Severa.

Work type

Work hours in Visma Severa are reported using a work type. You can get the list of available work types with GET /phases/{guid}/worktypes.

You can try to map the work types by name from the 3rd party application to Visma Severa or have it preconfigured, similar to the project phase.

Insert work hour

Once you know the "guid" of referenced user, project phase and work type, you’re ready to insert a work hour using POST /workhours endpoint. The request payload looks like the following:

A request to `POST /workhours` refers to existing user, project phase and work type.
{
  "eventDate": "2020-11-12",
  "description": "Ad setup for Black Friday campaign",
  "quantity": 7.5,
  "phase": {
    "guid": "7ffc8c0e-cbcd-1e9d-583f-986f9318da92"
  },
  "user": {
    "guid": "edb87bb4-bbd8-667e-5dd8-a09962ce49ae"
  },
  "workType": {
    "guid": "afd56169-82ab-8bc7-41c4-9ad10a05210f"
  }
}

As a result, you receive the newly created row including the "guid" for the workhour. Store this in the 3rd party application to be able to update or delete the row later.

Synchronize modifications in 3rd party application to Visma Severa

Whenever the data changes in the 3rd party application, the changes should be reflected in Visma Severa. Propagate changes using PATCH /workhours/{guid}, see Updating. Delete work hours using DELETE /workhours/{guid}.

There are limits to what can be changed. For example, a day can be closed, or a work hour can be invoiced, in which cases the hours cannot be modified.

Send invoices and monitor payments

Transferring invoice sending and payment monitoring to outside of Visma Severa is a common use case. The invoice is created in Visma Severa based on work hours, project fees and travel expenses. Once the invoice is approved in Visma Severa, the 3rd party application takes over the sending and payment monitoring. Later, when the application notices a payment, it updates the invoice status in Visma Severa.

Model of invoices, invoice statuses and invoice rows

Visma Severa organizes invoice data into a few separate models. The main entry point is invoices. Invoices refer to invoice status, and the individual items of an invoice are stored as invoice rows.

flowchart TD I[Invoice] IS[Invoice Status] IR[Invoice Row] I --- IS I --- IR

Invoice consists of invoice status and invoice rows.

Invoice status workflow

Visma Severa allows customized invoice statuses. This allows tailoring the invoicing process for each business domain. At a minimum, there should be four statuses:

  • Draft - the invoice has not yet been finalized and is likely change
  • Approved - the invoice has been completed and is ready to be sent to the customer
  • Sent - the invoice has been sent to the customer and is awaiting payment
  • Paid - the invoice has been fully paid
flowchart LR D(Draft) A(Approved) S(Sent) P(Paid) D .-> A .-> S .-> P

At a minimum, four invoice statuses are needed for externalizing invoice sending and payment monitoring.

Get Approved invoices

The first step is to get the invoices in the Approved state from Visma Severa. They are invoices that are ready to be sent to the customer. The steps needed are:

  1. get the list of invoice statuses to find the target guid of the Approved state
  2. get invoices that match the desired state
  3. get invoice rows for matching invoices

The application would perform this process periodically, for example, every hour.

Get list of invoice statuses

To get a list of invoice statuses, make a request to GET /invoicestatuses. Store the result in an internal representation in the 3rd party application. The statuses are needed when updating invoices later.

Get invoices with Approved status

Get the list of invoices in Approved status, make a request to GET /invoices?invoiceStatusGuid={guid} and pass in the guid for the Approved status fetched earlier.

Get invoice rows

Once the invoices have been received, the individual invoice rows can be fetched with a request to GET /invoices/{guid}/invoicerows. This should be performed once for each invoice received in the previous step.

Update invoice Sent status, invoice number and reference number in Visma Severa

Now, the 3rd party application has received all Approved status invoices and related data. It then generates an invoice number and a payment reference number for each invoice. The application updates these numbers to Visma Severa and sets the status of such invoice to Sent. Then, the application proceeds with delivering the invoices to the customers.

To update invoice data, make a PATCH /invoices/{guid} request (see Updating). A guid is used to refer to the Sent invoice status.

Invoice number, reference number and status is updated using JSON Patch format.
[
  {
    "op": "replace",
    "path": "/status",
    "value": "0d0d19ef-216a-ecda..."
  },
  {
    "op": "replace",
    "path": "/number",
    "value": 45
  },
  {
    "op": "replace",
    "path": "/referenceNumber",
    "value": "10045"
  }
]

Update invoice Paid status in Visma Severa

Once the 3rd party application notices the invoiced amount has fully been paid, the application updates the invoice status in Visma Severa to Paid. This is done using request to PATCH /invoices/{guid} (see Updating.) A guid is used to refer to the Paid invoice status.

Invoice status is updated using JSON Patch format.
[
    {
        "op": "replace",
        "path": "/status",
        "value": "2d0a7e58-03fc-80bf..."
    }
]

Synchronize customers

Synchronizing customers to a 3rd party application is a common use case. This can be, for example, to use an email marketing automation software to automate sending emails.

Model of customers, contact persons and addresses

Visma Severa organizes customer data into a few separate models. The main entry point is customers. A customer can have contact persons. Both customers and contact persons can have addresses.

flowchart TD C[Customer] CP[Contact Person] A[Address] C --- CP C --- A CP --- A

Customers can have contact persons, and both of them can have an address.

In order to synchronize customer data, fetch customers, along with contact persons and addresses.

Fetch initial data

Start by fetching the results in their entirety from the following endpoints:

  • GET /customers
  • GET /contactpersons
  • GET /addresses

Remember that the results are potentially large and that they are paged. Use the highest possible value for rowCount, and keep sending more requests with increasing firstRow until you have receive all the data.

Once you have received everything, it’s time to link together the data from the three different endpoints. Each object contains a uniquely identifying "guid" property, and other objects can refer to each other using these identifiers.

Customer

A customer can be linked to a headquarter address by connecting the "headquarterAddress.guid" to a matching "guid" in received addresses.

flowchart TD C[Customer] A[Address] C-. headquarterAddress.guid .->A

A customer can be linked to a headquarter address using "headquarterAddress.guid".

Contact person

A contact person can be linked to a customer using "customer.guid" and the contact person’s address can be connected by with "addressGuid".

flowchart TD C[Customer] CP[Contact Person] A[Address] CP-. addressGuid .->A CP-. customer.guid ..->C

A contact person can be linked with a customer and an address using "customer.guid" and "addressGuid".

Use this knowledge of unique "guid" identifiers and references to translate the received data into a data structure in your 3rd party application. Make sure you store the original "guid" from Visma Severa to be able to update the rows later.

Periodically query for changed rows

Once you’ve received all the data once, you can use changedSince query to get only the added or modified rows. You can perform this query periodically, for example, once an hour.

sequenceDiagram participant A as Application participant C as /customers A->>C: GET /customers C->>A: all loop Once an hour A->>C: GET /customers?changedSince=... C->>A: changed end

After initially fetching all rows, only the changed rows are queried at a regular interval.

To avoid matching incoming data with a non-existent reference, retrieve the changed and added rows in reversed dependency order:

  1. addresses
  2. customers
  3. contact persons

Link the received changed and added rows with the existing data.

Deleted rows

In the case of a customer, contact person or address is deleted, the deleted row is not included in a changedSince query. Currently, the only way to take into account deleted rows is to fetch again the intiial data in its entirety, see which "guid"’s are no longer included in the results, and delete those from the 3rd party application.

Concepts

Authentication

Client credentials

The client id and client secret, collectively called the client credentials, are required to obtain an API access token. Client credentials are created in Visma Severa.

You can create up to 10 credentials. We recommend that you create separate credentials for each 3rd party application you integrate with.

If you integrate Visma Severa with an email marketing software and a reporting service, you’d create two credentials and dedicate one for each service.

See From Zero to First API Call for instructions on how to create client credentials.

Error: Invalid client credentials

In case of an invalid client id and client secret, Visma Severa REST API responds with the HTTP status code 401. When this happens, you should review the correct values for client id and client secret under Settings and REST API in Visma Severa. Make sure the values are entered according to the instructions in From Zero to First API Call.

Using invalid client id or client secret results in HTTP status 401 response and an error message.
401 Unauthorized

{
  "error": {
    "httpStatusCode": 401,
    "type": "AuthenticationRequired",
    "details": [
      {
        "message": "No client id with given credentials found or client id is disabled or inactive.",
        "location": null
      }
    ]
  }
}

Client id

The client id is a unique string that identifies the 3rd party application calling Visma Severa REST API. The client id is used during the authentication flow. Each 3rd party application should have its own client id. The client id is part of the client credentials.

See From Zero to First API Call for instructions on how to create client credentials and to obtain an API access token.

Client secret

The client secret is used during authentication to obtain an API access token. The client secret is part of client credentials.

See From Zero to First API Call for instructions on how to obtain an API access token.

Integration partner

If you’re using an external partner to implement the integration to Visma Severa, it’s recommended that you give their contact information to Visma to help in troubleshooting. Integration partner contact details can be filled under client credentials.

Integration partner details can be filled under client credentials.

See From Zero to First API Call for instructions on how to create client credentials.

Access token

Visma Severa REST API uses access tokens to verify a caller has the permission to access an API. You can obtain an access token by calling POST /token. The access token is then sent in the HTTP header of each subsequent request.

See From Zero to First API Call for instructions on how to obtain an access token and use it to authenticate calls.

Error: Invalid access token

In case of an invalid access token, Visma Severa REST API responds with the HTTP status code 401. When this happens, you should make sure the access token is entered according to the instructions in From Zero to First API Call. You should also check that the access token has not expired.

Using invalid access token results in HTTP status 401 response and an error message.
401 Unauthorized

{
  "error": {
    "httpStatusCode": 401,
    "type": "AuthenticationRequired",
    "details": [
      {
        "message": "Authorization header is missing, given access token is not valid, wrong Client_Id or Client is not allowed to use api.",
        "location": null
      }
    ]
  }
}

Token expiration

The access token received from POST /token is valid for a fixed length of time. By default, the expiration time is 1 hour.

The exact amount of seconds the token is valid and the last valid timestamp in UTC time is included in the result from POST /token.

Response from `POST /token` contains access token expiration information.
{
  ...
  "expires_in": 3600.0,
  "expires_utc": "2020-12-01T12:42:38+00:00",
  ...
}

You can refresh the access token using a separate endpoint and a refresh token included in the POST /token response.

Refresh access token

An API access token is valid for a fixed amount of time. Visma Severa REST API provides a way to continue the session beyond the expiration time. To continue the session, call POST /refreshtoken and pass the refresh_token value from the original response to POST /token.

The response to POST /token contains the refresh token and its expiration information. The refresh token is valid for 2 hours by default.

Response to `POST /token` contains refresh token and its expiration information.
{
  ...
  "refresh_token": "OAAxADYAMwAxAGIAMQAwAC0A...",
  "refresh_token_expires_in": 7200.0,
  "refresh_token_expires_utc": "2020-12-01T13:42:38+00:00"
  ...
}

In the call to POST /refreshtoken, the refresh token is passed in as a JSON string in the payload. Make sure to pass the token wrapped in double-quotes (").

POST /refreshtoken
Content-type: application/json
client_id: company_client_id_here

"OAAxADYAMwAxAGIAMQAwAC0A..."

If you reached the expiration time of the refresh token, POST /refreshtoken is no longer an option, and you should re-authenticate using POST /token.

Changed since

Some results are large, and instead of getting all the rows, it’s more efficient to only get the rows changed since the last retrieval. For selected endpoints, Visma Severa REST API provides a way to get new or changed rows since a given timestamp.

Query for changed rows by setting the changedSince query parameter. The parameter accepts a timestamp and will return only rows added or changed after the given timestamp. The timestamp is inclusive, and the result includes the rows created or modified on the exact timestamp queried.

The timestamp must follow a form supported by DateTimeOffset. For example, you can use yyyy-MM-ddTHH:mm:ss.fffZ in UTC time.

For example, to get the user rows that have changed since 2020-11-30 12:34:12 UTC time, you’d make the following request GET /users?changedSince=2020-11-30T12:34:12.000Z.

See also Synchronize customers to 3rd party application for an example of using changedSince with customer data.

Client generation

Visma Severa REST API documentation is based on OpenAPI 3.0, which allows the usage of 3rd party client generators to automatically create source code for accessing the API.

Client generators require either an address to or an actual .json file to base the client on. The latest production API version .json file is available at

https://api.severa.visma.com/rest-api/openapidocs/v0.2/doc.json

Environments

Production environment

Visma Severa REST API is available at:

https://api.severa.visma.com/rest-api

Test environment

It’s beneficial to separate development of the application and production use. Visma Severa provides a test environment where it’s safe to modify the data during development.

Contact local support to get access to the environment and to be able to create client credentials and test data.

After you’ve created client credentials, the test environment is available at:

https://api.severa.stag.visma.com/rest-api

Errors

In case an operation fails, Visma Severa REST API responds with an error message. The response is sent using one of the error HTTP status codes defined in RFC 2616. The payload contains detailed information about the error in both human and machine-readable form.

For example, trying to use an invalid access token results in 401 HTTP status code and an error message.

Error responses provide details in both human and machine-readable form.
401 Unauthorized

{
  "error": {
    "httpStatusCode": 401,
    "type": "AuthenticationRequired",
    "details": [
      {
        "message": "Authorization header is missing, given access token is not valid, wrong Client_Id or Client is not allowed to use api.",
        "location": null
      }
    ]
  }
}

The error message contains the following fields:

Field Description
error.httpStatusCode The HTTP status code the response was sent with. Uses HTTP status codes defined in RFC 2626. For example 401 Unauthorized.
error.type The type of error that occurred in Visma Severa. See the accompanying table for a list of possible values.
error.details An array of objects each describing the error in more detail. It may contain multiple items, for example, in case of a validation error.
error.details[].message A human-readable description of the occurred error.
error.details[].location In case of validation errors, contains the path of the offending value.

The structure of an error message.

The error.type value describes in more detail what was the cause of the error. The possible values are:

error.type value Description
"InternalSystemError" default value
"AuthenticationRequired"  
"AddonMissing"  
"FeatureIsNotEnabled"  
"InvalidParameter" request contains invalid parameter
"InvalidOperation" requested operation was invalid
"InvalidRequest" request is invalid, for unknown reason
"InsufficientApiScope"  
"ConfigurationError" something is wrong with the client organization settings
"UserLicenseType"  
"TermsOfServiceNotApproved"  
"HttpsRequired"  
"OrganizationNotActive"  
"PermissionDenied"  
"TrialExpired"  
"NotAvailableInTrial"  

Possible values for error.type in an error message.

Paging

Visma Severa REST API delivers large results using pages. The result of a single call contains 100 items by default. You can increase the number of items by setting the rowCount query parameter. The maximum value for rowCount is 1000. Omitting rowCount is the equivalent of setting rowCount=100.

You can determine if there are more items left by comparing the result size to rowCount. If the result is smaller than rowCount, then you’ve reached the end. Otherwise, you should make another request.

The next chunk of items can be fetched by setting the firstRow query parameter. The parameter makes the result set start on the requested 0-based index instead of the beginning of data. Omitting firstRow is the equivalent of setting firstRow=0.

For example, when fetching 230 customers using rowCount=100

  • The first call would have no firstRow at all (or firstRow=0) and return 100 rows
  • The second call would have firstRow=100 and return 100 rows
  • And finally, the third call would have firstRow=200 and return 30 rows. You would now this is the last chunk since the number of returned rows is less than the requested rowCount.

Some endpoints allow larger values for rowCount than 1000. SEE the API Specification for details.

Rate limit

Visma Severa REST API is rate limited, and a 3rd party application can make at most 10 calls per second.

If an application exceeds the limit, the API responds with HTTP status 429 and an error message:

Status: 429 Too Many Requests 

API calls quota exceeded! maximum admitted 10 per Second.

Exceeding rate limit causes HTTP status 429 and an error message.

Strategies to avoid hitting rate limit

Instead of getting a large result set, you can use endpoints that support changedSince parameter to only get recently added and modified items. This way, the application can get the desired data using fewer calls. See Synchronize customers to 3rd party application for an example of this approach.

Scopes

Visma Severa REST API supports fine-grained access control through permission scopes. When creating client credentials, the administrator defines which permissions are allowed for that set of credentials. And later, when obtaining an API access token, the caller requests a subset of those permissions to be granted for the access token. The caller cannot request permission that has not been allowed for that set of credentials.

The scopes are organized by topic and operation. Topics can be, for example, customers, projects and invoices. Operations are read, write and delete.

Topic Scope names Description
Customers customers:read, customers:write, customers:delete customer resources
Projects projects:read, projects:write, projects:delete project resources
Invoices invoices:read, invoices:write, invoices:delete invoice resources
Hours hours:read, hours:write, hours:delete work hour resources
Travels travels:read, travels:write, travels:delete travel expense related resources
Fees fees:read, fees:write, fees:delete project fee related resources
Activities activities:read, activities:write, activities:delete activity resources
Absences absences:read, absences:write, absences:delete absences and private activities
Users users:read, users:write, users:delete user resources
Organization organization:read, organization:write organization-level resources
Settings settings:read, settings:write, settings:delete settings resources
Files files:read files

For example, if an integration partner is used to implement an email marketing automation software integration, client credentials with the permission customers:read can only be added for them. This way, sensitive information, such as hours and invoices, is not accessible.

See From Zero to First API Call for an example of obtaining an access token and requesting permissions.

Error: Requested scope not allowed for client credentials

If you’re trying to request a scope during a call to POST /token that’s not enabled for the client credentials you’re using, Visma Severa REST API responds with a 401 Unauthorized. You can check the response header X-Accepted-OAuth-Scopes for a list of scopes that are available for this set of client credentials.

To fix this, you should configure the enabled scopes in Visma Severa.

Example of requested scope not allowed
401 Unauthorized
X-Accepted-OAuth-Scopes: customers:read

{
  "error": {
    "httpStatusCode": 401,
    "type": "AuthenticationRequired",
    "details": [
      {
        "message": "Requested scope 'customers:write' is not allowed for the api client.",
        "location": null
      }
    ]
  }
}

Error: Insufficent permissions for operation

If you’re making a call to an endpoint that requires permission that the API access token currently doesn’t have, Visma Severa REST API responds with a 403 Forbidden response. The response contains X-Accepted-OAuth-Scopes header that lists the required permissions. The X-OAuth-Scopes header lists the permissions currently assigned to the access token.

You should request a new API access token using POST /token with the necessary scopes enabled.

Example of insufficient permission for operation
403 Forbidden
X-Accepted-OAuth-Scopes: projects:read
X-OAuth-Scopes: customers:read

{
  "error": {
    "httpStatusCode": 403,
    "type": "InsufficientApiScope",
    "details": [
      {
        "message": "Scope needed: projects:read",
        "location": null
      }
    ]
  }
}

Search within text

Visma Severa REST API supports searching for a matching string across multiple fields in the target resource. Search by setting the textToSearch query parameter.

The search is case insensitive and matches inside strings. For example, searching for user “Jon” matches “Jones”. Also, the specification of which fields get searched varies from one endpoint to another.

For example, to search for a customer that matches the string “2637474-2” either in customer name, number or address or company VAT number, call GET /customers?textToSearch=2637474-2

The searched fields vary from one endpoint to another. For a full list, see the table below.

Endpoint Searched fields
/accessrightprofiles permission profile name
/activities activities’ name, description, owner name, project name, customer name, participants names
/activitytypes activity type name
/allusers/resourcingavailability user name or keywords
/allusers user name or keywords
/bankaccounts bank account name
/businessunits business unit name
/calendarresources resource name
/communicationtypes communication type name
/contactpersons contact person’s name or communication method (i.e.phone number or email address)
/contactroles contact role name
/costaccounts cost account name or identifier
/costcenters cost center name or identifier
/customers/{customerGuid}/collaborationnotes notes
/customers/{customerGuid}/contactpersons contact person’s name or communication method (i.e.phone number or email address)
/customers/{customerGuid}/projects project name, number, keywords or customer name
/customers/{customerGuid}/salesnotes notes
/customers customer name, number or address, company vat number
/global/links link name or url
/industries industry name
/invoicerows/{invoiceRowGuid}/projectfees name or description
/invoicerows/{invoiceRowGuid}/projecttravelexpenses description
/invoicerows/{invoiceRowGuid}/reimbursedprojectfees name or description
/invoicerows/{invoiceRowGuid}/reimbursedprojecttravelexpenses name or description
/invoices/{invoiceGuid}/projectfees name or description
/invoices/{invoiceGuid}/projecttravelexpenses description
/invoices/{invoiceGuid}/reimbursedprojectfees name or description
/invoices/{invoiceGuid}/reimbursedprojecttravelexpenses name or description
/invoices/{invoiceGuid}/uninvoicedprojectfees name or description
/invoices/{invoiceGuid}/uninvoicedprojecttravelexpenses description
/invoices invoice number, reference number, project name, customer name, total value (excl.taxes)
/invoicestatuses invoice status name
/keywords keyword
/kpiformulas  
/leadsources lead source name
/marketsegments market segment name
/overtimes overtime name
/permissionprofiles permission profile name
/personal/links link name or url
/phases/{phaseGuid}/phasemembers user name
/phases/{phaseGuid}/phasememberswithresourcingavailability user name
/phases/{phaseGuid}/worktypes work type name or code
/pricelists pricelist name
/pricelistversions/{pricelistVersionGuid}/productprices Product name
/pricelistversions/{pricelistVersionGuid}/travelprices Product name
/products name or code
/projects/{projectGuid}/collaborationnotes notes
/projects/{projectGuid}/productprices Product name
/projects/{projectGuid}/productsforproject name or code
/projects/{projectGuid}/projectfees name or description
/projects/{projectGuid}/projectproducts name or description
/projects/{projectGuid}/projecttravelexpenses description
/projects/{projectGuid}/projectworktypes work type name
/projects/{projectGuid}/salesnotes notes
/projects/{projectGuid}/travelexpenses name or code
/projects/{projectGuid}/travelprices Product name
/projects/{projectGuid}/worktypesforproject name or code
/projects project name, number, keywords or customer name
/projectstatustypes CaseStatusType name
/projecttaskstatuses activity type name
/proposalstatuses proposal status name
/proposaltemplates proposal template name
/quicksearch/customercontacts  
/quicksearch/customers  
/quicksearch/files  
/quicksearch/invoices  
/quicksearch/projects  
/quicksearch customers, contacts, projects, invoices and files
/resources resource name
/resourcingusers user name or keywords
/rootphaseswithhierarchy phase name, project name or number, customer name
/salesaccounts cost account name or identifier
/salescases project name, number, keywords or customer name
/salesstatustypes sales status type name
/timeentrytypes time entry type name
/travelexpenses name or code
/travelreimbursements/{travelReimbursementGuid}/projecttravelexpenses description
/travelreimbursements travel reimbursement number
/travelreimbursementstatuses travel reimbursement name
/uninvoicedprojects project name, number, keywords or customer name
/users/{guid}/potentialsupervisors user name or keywords
/users/{userGuid}/calendargroups Calendar group name
/users/{userGuid}/phasetreephases/joinable phase name, project name or number, customer name or number
/users/{userGuid}/phasetreephases phase name, project name or number, customer name or number
/users/{userGuid}/projectfees name or description
/users/{userGuid}/projecttravelexpenses description
/users user name, code, email or keywords
/worktypes work type name or code

The textToSearch query parameter in a GET request can be used to search across multiple fields in the target resource.

Sorting

Visma Severa REST API supports sorting a result set by given set of fields. The fields can be sorted in ascending or descending order. Sort by setting the sortings query parameter and passing in the sorting specification.

The sorting specification is described as an array. Each element in the array is an object that contains two properties: key and value. The sorted field name is placed in key and the desired sorting order is placed in value. The supported sorting orders are "Asc" and "Desc".

{
  sortings: [
    {
      key: "lastName",
      value: "Asc",
    },
  ],
}

The array of objects is flattened into a URL query string by converting array items into indexed array subscripts sortings[0] and object properties into named subscripts sortings[0][key].

?sortings[0][key]=lastName&sortings[0][value]=Asc

For example, getting the list of all users and sorting the result by lastUpdatedDateTime and createdDateTime, so that updated time is sorted in descending order and created time is sorted in descending order, you’d pass the following sorting specification:

{
  sortings: [
    {
      key: "lastUpdatedDateTime",
      value: "Desc",
    },
    {
      key: "createdDateTime",
      value: "Asc",
    },
  ],
}

That would be flattened into the URL query string: "GET /users?sortings[0][key]=lastUpdatedDateTime&sortings[0][value]=Desc&sortings[1][key]=createdDateTime&sortings[1][value]=Asc"

Synchronizing data

There’s often a need to access Visma Severa data in a 3rd party application or to reflect changes in the 3rd party application in Visma Severa. In either case, one system acts as the master and its data is synchronized to the dependent system. Changes, additions and deletions in the master system are reflected in the dependent system within a reasonable delay.

Visma Severa as master

Exporting and synchronizing Visma Severa data to a 3rd party application involves fetching the initial data and then periodically refreshing it.

Typically the desired information involves data from multiple endpoints. For example, customers are closely related to contact persons and addresses. You should synchronize the data from all related endpoints.

To export and synchronize:

  1. Initially, fetch all the data from an endpoint. Large results are paged, and you should query for more pages with increasing firstRow until you’ve received the result in its entirety.
  2. Link data from multiple endpoints into an internal representation in the 3rd party application. Result rows refer to each other using using unique "guid" identifiers. Store the "guid"’s in the internal representation to enable updating and deleting the rows later.
  3. Periodically query for changed and added rows in Visma Severa using a changedSince=? query. Reflect the changes accordingly in the internal representation. It’s good to perform this frequently, for example, once an hour.
  4. Less frequently, re-fetch all the data from an endpoint, and compare the received "guid"’s to the ones already in the internal representation. If some row is no longer present in the result from Visma Severa REST API, it has been deleted and can be removed from the 3rd party application.

See Synchronize customers to 3rd party application for a detailed example of this process with customer data.

3rd party application as master

Importing and synchronizing 3rd party application data to Visma Severa involves pushing the initial data and then making sure changes are reflected in Visma Severa.

Many times the inserted data refers to existing rows in Visma Severa. Therefore, to determine the right values for referenced "guid"s, data must be first synchronized from Visma Severa to the 3rd party application. This synchronized data must also be mapped to corresponding rows in the 3rd party application. For example, the email address can be used to match a user in the 3rd party application to a user in Visma Severa.

Importing data from 3rd party application

  1. Synchronize referenced data to 3rd party application. See Synchronizing data with 3rd party application.
  2. Map referenced items between the 3rd party application and Visma Severa.
  3. Insert all new data using POST calls.
  4. To reflect changes in 3rd party application to Visma Severa, periodically:
    1. Synchronize referenced data.
    2. Update changed values in the 3rd party application to Visma Severa using PATCH request. See Updating.
    3. Delete rows removed from 3rd party application using DELETE request.

Notice that some data cannot be changed after it has reached a certain state. For example, work hours can’t be changed after they are invoiced.

Updating

Visma Severa REST API allows updating existing records. For endpoints that support it, send a PATCH request and pass a specification of changes using JSON Patch format.

The JSON Patch format describes changes using an array of operations. Each operation describes a change to a value in the existing document.

JSON Patch format describes changes using an array of individual operations.
[
  {
    "op": "replace",
    "path": "/fieldName",
    "value": "New value"
  },
  {
    ...
  },
  {
    ...
  }
]

The JSON Patch specification describes operations such as add, move, copy, but in Visma Severa REST API, only replace ("op": "replace") is supported.

In the change description, "path" describes the property in the existing document that is to be changed. The property is described using JSON Pointer notation. And, "value" contains the new value to be assigned to that property.

For example, to change the last name of the user identified with "guid": "edb87bb4-bad8-687e-5dd8-a09262ce49ae" to “Smith”, send the following request:

The last name of a user is changed by sending a `PATCH` request and a change specification.
PATCH /users/edb87bb4-bad8-687e-5dd8-a09262ce49ae
client_id: ...
Authorization: ...
Content-Type: application/json

[
  {
    "op": "replace",
    "path": "/lastName",
    "value": "Smith"
 }
]

Versions

Visma Severa REST API uses URL versioning scheme to differentiate between different releases. The URL path contains a v-prefixed version string to identify the release.

For example, two different releases of Visma Severa REST API are located at:

https://api.severa.visma.com/rest-api/v0.1/

https://api.severa.visma.com/rest-api/v0.2/

Versioning is used in all routes, except /heartbeat which is used for server availability and is not version dependent.