Webhooks are a mechanism allowing Brightpearl to send an HTTP request to a URI of your choice when some event takes place affecting a customer account. This mechanism can be used to develop integrations that are more efficient and closer to real-time than integrations based on polling and scanning.

There are a couple of concepts you will need to understand when building an integration which relies on Brightpearl webhooks: resource events and webhook registration.

Resource events

Brightpearl's internal systems are built around the concept of resource events. Whenever a resource is created, modified or destroyed a resource event is broadcast to any interested system.

Webhooks allow remote systems to subscribe to our internal resource events. A full list of the resource events that are available to subscribe to is here and we expect this list to grow over time.

Event naming

Resource events have a hierarchical naming structure which looks like this:

{resource type}.{lifecycle event}.{specifier}

A resource type is the name of the resource (Goods-Out Note, Product etc) and lifecycle event is one of created, modified or destroyed


Some modified events have an optional specifier which provides systems with more information about what actually happened.

So the event:


tells you that a Product resource has been changed and what has changed is that the level of on-hand stock has been altered.

Registering a webhook

In order to have Brightpearl contact your system when a certain type of event occurs, you must register a webhook using

/integration-service/webhook POST

When POSTing a webhook, you must provide the following information:

  • An absolute URI to call when the event occurs
  • An HTTP method for us to use (limited to GET, POST, PUT, DELETE)
  • An optional body (if the HTTP method is PUT or POST)
  • A content type for us to set when calling your URI (text/xml etc) if have set the HTTP method to PUT or POST
  • The event you are interested in subscribing to (product.created etc)
  • The Quality of Service you require for the transport.

For full details of the fields you need to supply and detailed examples, please refer to the webhook POST documentation.

Template variables

A very limited templating system is in place which will allow us to insert information into your webhook's URI and/or body.

The following variables must appear at least once in your URI and/or body so that we can be sure your webhook has sufficient information to take sensible actions.

Variable name Purpose
${resource-type} Will be replaced with the type of Brightpearl resource affected (goods-out-note, product etc)
${resource-id} The unique ID or ID Set (see below) of the affected resource
${lifecycle-event} created, modified or destroyed
${account-code} The unique identifier of the Brightpearl account to which the resource belongs

You also have the option of using the following:

Variable name Purpose
${full-event} The full event (product.modified.on-hand-modified, order.created etc)
${raised-on} The ISO 8601 date/time at which the event was first raised internally
${brightpearl-version} The version of the Brightpearl account (4.39.0 etc) when the event was first raised internally [DEPRECATED]

Resource wildcards

When subscribing to events, you can omit the lifecycle portion of the event name to receive all types of lifecycle event for that resource type. E.g.


will subscribe to all product related events.

ID Sets

When POSTing a new webook, you may set the optional idSetAccepted field to true. If you do this, the ${resource-id} variable in your template will be substituted with an ID Set rather than a single ID .

This can lead to vastly reduced numbers of callbacks - if you do not set this field to true, an event that affects 1,000 resources will cause 1,000 callbacks to your system. If you set this to true, you will receive a single callback with an ID Set identifying the affected resources.

More information on ID Sets can be found here

Quality of Service (QoS) - retry logic

In 2017 we introduced the Quality of Service level parameter and level 1 QofS. This means that when you register for a webhook you can choose which level to use.

Level 0

This applies an “at most once” retry policy. Any webhooks registered prior to the introduction of the qualityOfService parameter will use this level. We will make up to five attempts to call your specified URI and assume that your integration cannot tolerate duplicate notifications. We will only retry in the event of:

  • Your system returning an HTTP 503 (too busy) status code.
  • A network level problem preventing us establishing an HTTP connection to your URI (DNS issues, timeout while trying to connect etc)

We will immediately stop attempting to call your URI and consider the callback failed if:

  • Your system returns a 1xx, 4xx or any 5xx code other than 503
  • Your system returns a status code outside the 100-599 range
  • Your system returns a 3xx code other than 301, 302 or 307 (see redirects below)
  • Your system stops sending data after the HTTP connection has been established for more than five seconds.

Any 2xx status code is considered a success.

Level 1 - multiple retries over 48 hours

This level uses an “at least once” policy with a longer retry window. It assumes that your integration can handle duplicate events, which is preferable to a lost event. We will retry any call that does not result in a success or “client error” HTTP status code (2xx or 4xx). Any other condition is considered a potential failure and the call will be retried for up to 48 hours. We use an exponential backoff strategy to allow for low latency in the case of short outages or transient errors (e.g. high network traffic on your servers) and lower load in the case of longer outages.

We will retry a call in the event of:

  • Your system returns any HTTP status code other than 2xx or 4xx.
  • A network level problem preventing us from receiving a response.

A call is considered to have permanently failed if:

  • Your system returns a 4xx status code.
  • Repeated attempts to send the call fail for 48 hours.

Permanently failed calls and successfully made calls are removed from our systems and will never be retried.


We will honour up to three redirect hops. I.e. you may return valid 301, 302 or 307 responses up to three times but the fourth must result in a URI that doesn't return a 3xx code. This policy gives you some flexibility in managing your URIs but prevents our calls getting stuck in a redirect loop.

SSL certificates

If you specify a callback URI with an HTTPS scheme, your SSL certificate must pass all the checks here

We will not connect to systems with self-signed SSL certificates.


We will always encode calls to your system as UTF-8.


It is your responsibility to make sure any body templates you provide in your webhooks are parseable according to the content type you specify. For example, if you specify that we should send the text/xml content type header, you need to make sure that your body template is valid XML. We will not attempt to validate the content before we send it to you.

Changing webhooks

If you need to change the data in your webhook, you must issue a webhook DELETE and then a new webhook POST.

Best practices for webhook handling

  • Respond to webhook requests as quickly as possible

    You should do as little work as possible before returning a 200 OK response. For example, if you need to perform computations or make calls to external systems (including Brightpearl) you should add the event to a work queue and process that queue separately from your webhook handler.

    We may enforce a maximum response time as low as 3 seconds in the future, after which we may consider the request to have failed and start retrying. When too many events queue up waiting to be sent, we will start dropping the oldest ones to make space.

  • Handle duplicate events

    Webhook endpoints might occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent.

Have more questions? Submit a request