Webhooks (Beta)

🚧

Sandbox beta

Webhooks is currently in beta stage and only exist in our Sandbox environment. Therefore, this functionality is subject to change at any time and we do not guarantee any backwards compability at this time. Please try this functionality out, if you have any questions or feedback, don't hesitate to let us know at [email protected].

Webhooks will let your subscribe to events in Visma eAccounting, notifying you whenever a event is triggered within your subscription. We will send a HTTP POST payload to the URL configured in your subscription.

With webhooks we will inform you when customer data changes so you don't have to poll us anymore. It will increase the efficiency and make your apps upp to date, in real time!

Events

Our events are represented by the most used entities in Visma eAccounting:

Event nameDescription
ArticleTriggered whenever a article is created, changed or deleted
CustomerTriggered whenever a customer is created, changed or deleted
CustomerInvoiceTriggered whenever a customer invoice is created or changed
CustomerInvoiceDraftTriggered whenever a customer invoice draft is created, changed or deleted
OrderTriggered whenever an order is created, changed or deleted
SupplierTriggered whenever a supplier is created, changed or deleted
SupplierInvoiceDraftTriggered whenever a supplier invoice draft is created, changed or deleted
QuoteTriggered whenever a quote is created, changed or deleted
VoucherTriggered whenever a voucher is created, changed or deleted
WebshopOrderTriggered whenever a web shop order is created, changed or deleted
AccountTriggered whenever a bookkeeping Account is
created, changed or deleted
FiscalYearTriggered whenever a fiscal year is
created, changed or deleted
CostCenterTriggered whenever a cost center is
created, changed or deleted
CostCenterItemTriggered whenever a cost center item is
created, changed or deleted
..more to come..more to come

Webhooks And Subscriptions

As a third party application provider, you generally have more than one customer. The webhook and its subscriptions are in the context of a single Visma eAccounting customer, heres a illustration of how a multiple customer webhook setup looks like:

1764

This setup allows you to set up your webhooks and subscriptions however you like. If you want one webhook per subscription - fine! If you want one webhook per customer with all subscriptions gathered under the same webhook - also fine!

As of the time being, webhooks and subscriptions are managed through the eAccounting API, within the /v2/webhooks endpoints. The following endpoints are available:

URLDescription
GET /v2/webhooksGets all webhooks for the authenticated company with standard pagination
GET /v2/webhooks/{webhookId}Gets a single webhook
POST /v2/webhooksPosts a webhook with subscriptions.
PUT /v2/webhooks/{webhookId}Updates a single webhook with subscriptions
DELETE /v2/webhooks/{webhookId}Deletes a single webhook with subscriptions

The request payload when posting or replacing a webhook with subscription looks like this:

NameDescriptionRequiredRead OnlyData Type
IdentifierUnique Identifier of the entity in the notificationfalsetrueGuid
EndpointCallback URL that we will post subscribed events to. HTTPS is requiredtruefalseString (With URL validation)
DescriptionInternal description for youfalsefalsestring
ClientIdYour Client Idfalsetruestring
AuthenticationKeyIf you want authentication on your notifications, provide header name herefalsefalsestring
AuthenticationValueIf you want authentication on your notifications, provide header value herefalsefalsestring
SigningKeyIf provided, we will sign the payload with this keyfalsefalsestring
ActiveSet this to true if you want to activate this webhook and its subscriptions. If false, it will be saved and prepared but inactive. Default is falsefalsefalsebool
SubscriptionsYour webhook subscriptions. List each entity you want to subscribe totruefalseArray
CreatedUtcTimestamp when webhook was createdfalsetrueDateTime
ModifiedUtcTimestamp when webhook was latest modifiedfalsetrueDateTime

If you POST or PUT a webhook with Active set to true, we'll make a test request towards your registered endpoint. If you don't reply with a status code in the 200-299 range, we'll reply with a Bad Request (400). Therefore, you should have your webhook endpoint ready before posting it.

Authentication and Signing

We strongly recommend you to provide authentication and signing key to bump up the security on your webhook traffic. The AuthenticationKey represents the header name. The standard name "Authorization" works prefectly fine, but if you want to provide a header name of your own, feel free to do so. AuthenticationValue represents the header value.

We also offer the possibility for you to provide a signing key. Before sending the webhook, we combine the notification properties Action, Entity, Identifier, ModifiedUtc and Url with a delimiter consisting of a under score (_) into a string and use SHA-256 with your provided cryptographic signing key to generate a hash signature.

Here's a example of how the raw string combination looks like:

Update_Article_4584be5b-71a7-41e4-b181-c2d775a132ac_2035-05-15T11:24:25.3052213Z_

We send that hash signature in a header named X-Hub-Signature with a value of sha1=[hash].

When receiving the webhook on your end, save the signature. Create the same string as shown above based on the property values of the incoming webhook. Use the same SHA-256 cryptography to calculate a hash on your own. Compare each byte in the array with the one we provide. If each byte is alike, your data is untouched and safe. Here's a code example on how to verify the signature in C#:

using System;
using System.Security.Cryptography;
using System.Text;

namespace Example
{
  public class VerifySignature
  {
    private const string signingKeyString = "ThisIsABadKey";
      
    public void Verify(WebHookDto webHook, string signatureHeaderValue)
    {
      string stringToVerify = $"{webHook.Action}_{webHook.Entity}_{webHook.Identifier}_{webHook.ModifiedUtc}_{webHook.Url}";
      
      UTF8Encoding encoding = new UTF8Encoding(false);
      byte[] signingKeyByteArray = encoding.GetBytes(signingKeyString);
      byte[] signature = Convert.FromBase64String(signatureHeaderValue);
      byte[] hash;
      
      using (HMACSHA256 hmac = new HMACSHA256(signingKeyByteArray))
      {
        hash = hmac.ComputeHash(encoding.GetBytes(stringToVerify));
      }
      
      for (int i = 0; i < hash.Length; i++)
      {
        if (hash[i] != signature[i])
        {
      	  throw new Exception("Invalid payload");
        }
      }
    }
  }
}

Notifications

When you have a active webhook with subscriptions, we'll notify you when that entity is changed in Visma eAccounting. A notification look like this:

NameDescriptionData Type
IdentifierUnique Notification Id provided by eAccountingGuid
VismaCustomerIdUnique Visma Customer Id provided by eAccountingGuid
EntityName of the entityString
ActionType of action (Created/Changed/Deleted)String
UrleAccounting API URL to fetch entity changesString
ModifiedUtcUnique time stamp of the notificationDateTime
RetryAttemptAttempt number. Starts with 0Int

Retry Policy

We understand that services can be unresponsive some times. Our retry policy takes care of that for you. If you don't reply to our notification requests with a status code in the 200-299 range, we'll interpret that as a failed request. We will try to send the notification again, incrementing the RetryAttempt property once. We will make five attempts on each notification before deleting it. Each attempt will be delayed according to this schedule:

Retry AttemptDelay Added In SecondsInformation
11
217
3300
45000
586400Notification will be deleted after this attempt and webhook will be disabled.

The best way to make sure you don't lose any notifications is to store them in a local queue directly, reply to us with a successful statuscode, then have code listening to the queue and act accordingly. This means your main service could be having downtime, but as long as your queue endpoint is responding, you'll have all your notifications on your end. If you don't respond after all our retries, the webhook will be inactivated automatically. If this was unintentional from your end, just activate the webhook again and it's up and running!