Webhooks (Beta)
Sandbox beta not operational
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 are no longer operational in Sandbox and you will be informed on this page if or when new information is available.
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 name | Description |
---|---|
Article | Triggered whenever a article is |
Customer | Triggered whenever a customer is |
CustomerInvoice | Triggered whenever a customer invoice is |
CustomerInvoiceDraft | Triggered whenever a customer invoice draft is |
Order | Triggered whenever an order is |
Supplier | Triggered whenever a supplier is |
SupplierInvoiceDraft | Triggered whenever a supplier invoice draft is |
Quote | Triggered whenever a quote is |
Voucher | Triggered whenever a voucher is |
WebshopOrder | Triggered whenever a web shop order is |
Account | Triggered whenever a bookkeeping Account is\ |
FiscalYear | Triggered whenever a fiscal year is\ |
CostCenter | Triggered whenever a cost center is\ |
CostCenterItem | Triggered whenever a cost center item is\ |
..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:
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:
URL | Description |
---|---|
GET /v2/webhooks | Gets all webhooks for the authenticated company with standard pagination |
GET /v2/webhooks/{webhookId} | Gets a single webhook |
POST /v2/webhooks | Posts 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:
Name | Description | Required | Read Only | Data Type |
---|---|---|---|---|
Identifier | Unique Identifier of the entity in the notification | false | true | Guid |
Endpoint | Callback URL that we will post subscribed events to. HTTPS is required | true | false | String (With URL validation) |
Description | Internal description for you | false | false | string |
ClientId | Your Client Id | false | true | string |
AuthenticationKey | If you want authentication on your notifications, provide header name here | false | false | string |
AuthenticationValue | If you want authentication on your notifications, provide header value here | false | false | string |
SigningKey | If provided, we will sign the payload with this key | false | false | string |
Active | Set 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 false | false | false | bool |
Subscriptions | Your webhook subscriptions. List each entity you want to subscribe to | true | false | Array |
CreatedUtc | Timestamp when webhook was created | false | true | DateTime |
ModifiedUtc | Timestamp when webhook was latest modified | false | true | DateTime |
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_https://eaccountingapi.vismaonline.com/v2/articles/4584be5b-71a7-41e4-b181-c2d775a132ac
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:
Name | Description | Data Type |
---|---|---|
Identifier | Unique Notification Id provided by eAccounting | Guid |
VismaCustomerId | Unique Visma Customer Id provided by eAccounting | Guid |
Entity | Name of the entity | String |
Action | Type of action (Created/Changed/Deleted) | String |
Url | eAccounting API URL to fetch entity changes | String |
ModifiedUtc | Unique time stamp of the notification | DateTime |
RetryAttempt | Attempt number. Starts with 0 | Int |
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 Attempt | Delay Added In Seconds | Information |
---|---|---|
1 | 1 | |
2 | 17 | |
3 | 300 | |
4 | 5000 | |
5 | 86400 | Notification 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!
Updated 4 months ago