# Using webhooks

Webhooks send notifications when changes occur in companies you monitor. You can use these notifications to automate workflows, update your systems, or trigger other actions based on company changes.

Your webhook endpoint must be publicly accessible. To restrict access, you can reject requests that do not originate from an IP address on your allowlist.

Webhook requests are sent from the following IP addresses:

  • 16.170.128.217
  • 13.48.226.236
  • 13.48.76.156

These IP addresses may change without notice. Make sure that you can update your allowlist when necessary.

# Events

When a change occurs, we send an HTTP POST request to your webhook endpoint. The request body contains a JSON payload.

# Sample event

A webhook event has the following format:

{
  "companyId": "918298037",
  "country": "NO",
  "patchId": "d8214b8c66cc4fe4f2413ab6e66a10fd35931a05c2c681f12cbe2b7fa70bbf9b",
  "createdDate": 1773038810293,
  "link": "https://api.proff.no/companies/register/NO/918298037"
}

# Duplicate events

The same change event may occasionally be delivered more than once. Deduplicate events by storing the patchId and ignoring subsequent events with the same value.

# Event order

Events may be delivered out of order. For example, a newer change may arrive before an older one. Use the createdDate field to determine which event is the most recent.

# Signature verification

All webhook requests are signed using HMAC-SHA256. The signature is calculated from the request body using the webhook's secret key.

A secret key is generated automatically when you create a webhook endpoint. The key cannot be changed. To rotate the secret key, you must create a new webhook endpoint.

The signature is included in the X-Proff-Signature header. Its value is prefixed with sha256= and contains the signature as a hexadecimal string.

The signature can be calculated in .NET as follows:

private static string ComputeHmacSignature(
    string payload,
    string signatureSecret)
{
    using var hmac = new HMACSHA256(
        Encoding.UTF8.GetBytes(signatureSecret)
    );

    var hash = hmac.ComputeHash(
        Encoding.UTF8.GetBytes(payload)
    );

    return Convert.ToHexString(hash);
}

# Response time

Process webhook requests as quickly as possible.

If an event requires complex processing, store the payload for background processing and immediately acknowledge receipt by returning a 200 OK response.

# Versioning

Webhook payloads do not use explicit versioning and may be extended with new fields. Your endpoint should handle unknown fields gracefully by ignoring them.

# Retries

Webhook requests that return most 4xx status codes are not retried. Requests that return a 5xx status code or do not respond within five seconds are retried according to the following schedule:

  • The first retry occurs after approximately two seconds.
  • The second retry occurs approximately four seconds after the first retry.

If the initial delivery and both retries fail, another delivery cycle begins approximately one hour after the initial attempt. This cycle follows the same retry schedule.

If all attempts in the second delivery cycle fail, no further retries are made.

Transient client errors

HTTP status codes 408 and 429 are considered transient errors and will be retried.

# Webhook types

Two webhook types are available:

  • Anemic (thin)
  • Fat (patch)

Webhooks are anemic by default. An anemic webhook payload contains a link that you can follow to retrieve the updated company data.

When the webhook type is set to patch, the payload includes an array named patch containing the updated data. The patch follows the RFC 6902 JSON Patch standard (opens new window) and can be used to update data in your systems.

Patch format

The patch always contains the complete set of changes. For example, if you select only Address as an event type but the company's telephone number also changes, both changes will be included in the patch.

WARNING

Patch payloads can be large. If you monitor many companies, consider whether you need the complete patch or whether an anemic webhook is sufficient.

# Event types

If you do not specify any event types, a webhook will be sent for every change affecting a company you monitor.

For example, if a new field is added to company records, you may receive an event for every monitored company.

If you specify one or more event types, webhooks are sent only when a change matches one of the selected types.

WARNING

We strongly recommend specifying one or more event types to avoid receiving unnecessary events.

A single webhook definition cannot use different event types for different companies. Create separate webhooks if you need to monitor different companies for different types of changes.

For example, one webhook can monitor address changes for one group of companies, while another monitors new annual accounts for a different group.

# Disabled webhooks

You can disable a webhook by setting enabled to false. A disabled webhook does not receive new events, and events awaiting retry will not be delivered.

# Automatically disabled webhooks

A webhook is automatically disabled if event delivery continues to fail after all retry attempts. This prevents repeated unsuccessful requests from affecting other webhooks.

After resolving the issue, re-enable the webhook to resume event delivery.