Skip to main content

Event exports

EVA supports bidirectional communication; sometimes, pulling data alone is just not the right fit for your integration. For instance, when you want to trigger a workflow when an order is paid, or send out emails when a shipment is sent. Event exports ("webhooks") provide a valuable toolset for integrations to achieve this.


Because EVA is a real-time, event-based platform, we export these updates in real-time. When you look at the fundamentals, it's just a matter of specifying the endpoint to which the updates should be routed and you're all set.

These event exports themselves are of a simple nature and CANNOT be altered to include more information. If additional data is required after receiving an export, you can use services such as GetOrder based on the ID as specified in the export.

Event export basics

Let's start you off with the basics of event exports: our main differentiators for event messages and the information the messages can include.

Event contents

The event export contains a bunch of identifiers, with our two main differentiators being Target and EventType. These two properties determine the nature of the event export.

The Target can be seen as the subject of the event export, while the EventType then defines what has happened for the Target. To make this clearer with an example: a Target can be Order, with Type being Created or Shipped.

A complete list of the possible targets and their respective event types can be found lower on this page at Possible targets and event types.

Properties

The body of the event contains the following properties:

PropertyTypeDescription
UIDStringUnique identifier for the event.
CreationTimeStringTime at which the event was created in UTC (in ISO8601 format).
TimezoneStringTimezone in which the event was created.
TargetStringEvent subject.
EventTypeStringActual event for the target.
IdentifierStringThe Target's EVA ID.
BackendIDStringThe target's Backend ID.
BackendSystemIDStringThe ID of the system where the BackendID originated from, ensuring a unique combination.
DataObjectAdditional data for the event. This will always be an object. However, the properties may vary, please see the example events below.

Best practices

It's possible to create an endpoint and have all events sent to it, unfiltered and unverified - it's easy, but inadvisable. So before you head off and create your endpoint and your configurations, there are several things we strongly advise you to take in mind.

Filter

For one, EVA already sends out thousands of events, per second. Your endpoint might be up to the challenge, but a few improvements to EVA onwards and the amount of events might have doubled. Queues will form and your flows will start getting delayed, in short: don't skip Event specification.


This filtering goes hand in glove with the creation of multiple endpoints: if you have critical business flows based on event triggers, create a second endpoint, or a third, or.. You can see where we're going with this. In the same vein, if you're performing BI based on events, create another dedicated endpoint.

Verify

Ensure you won't take just anyone's own Order paid event at face value with our two lines of defense: Authorization and Verification.


Monitor

Monitor if your events are reaching your endpoint and are being processed properly. You might have your own software already doing so, but you can also set up EVA's Event exports monitor.


Synced or async

If you kick-off certain business flows based on your webhooks, which then need to be completed before your endpoint responds with a 200 (OK) message, then we calls this as being processed in-sync. If your endpoint responds with the confirmation right away upon receipt, we consider it a-sync.


Because your other flows may take several seconds to finish up, we advise you to set it up a-sync. This avoids your webhooks being delayed due to the Exponential backoff.


Event export configurations

Now that we've got you covered on the principles of our event exports, it's time to jump into event export configurations.

Settings

First off, we've got two settings that enable event exports for your environment.

TitleValueDescription
EventExports:EnabledtrueThis setting enables event exports in general
EventExports:EnableEventExportConfigurationstrueThis additional setting unlocks the use of multiple endpoints
Unlocking multiple endpoints for existing environments

Most existing environments (pre-core 2.0.678) run solely on EventExports:Enabled, which limits you to a single endpoint. Although we do recommend you to diversify your endpoints, enabling the EventExports:EnableEventExportConfigurations setting for existing environments requires additional work by New Black. Please contact your TL to get this up and running for you.

Services

We provide a set of services that can be used for event export configuration. The most basic form of event export configuration is configured as follows:

CreateEventExportConfiguration
{
"Name": "BasicEventExportConfiguration",
"Status": "1",
"Endpoint": "https://hookb.in/je0Zbx07Wdt9dlMMmnzZ",
"Config": {
"ResponseMode": 1
}
}

This simple configuration only specifies an endpoint. This will receive all possible event exports, does not require authentication and does not care about the contents of your response message.

Status

Status indicates whether or not the configuration should be used:

ResponseMode

The response mode specifies what response EVA should expect when firing off webhooks towards this configuration:

Authorization

In the authorization object we can define either a StaticBearerToken (as specified by you, or us) or a StaticUnschemedToken. When given, EVA will use it as authentication towards the specified endpoint.

{
"Config": {
"Authorization": {
"StaticBearerToken": "",
"StaticUnschemedToken": ""
},
"ResponseMode": 1
}
}

Event specification

In the MessageTypes object we can specify what messages we want to export to the endpoint. Leaving it empty will export all possible event types. To exclude event types, use ExcludedMessageTypes instead. Only specifying TargetID will send all EventTypes for that target.

A complete list of possible Targets and EventTypes can be found a little lower on this page.

As a reminder, using this kind of filtering for your endpoint keeps it running smoothly.

{
"Config": {
"MessageTypes": [
{
"TargetID": 1, // 1 = order
"EventType": "created"
}
]
}
}
Using both MessageTypes and ExcludedMessageTypes

When specifying both MessageTypes and ExcludedMessageTypes, the result is MessageTypes minus ExcludedMessageTypes.

OU specification

In the IncludeOrganizationUnits object we can specify for what OU we want to export events to the endpoint. Leaving it empty will export the events for all possible OUs. To exclude OUs, use ExcludeOrganizationUnits instead.

{
"Config": {
"IncludeOrganizationUnits": [1, 2, 3]
}
}
Using both IncludeOrganizationUnits and ExcludeOrganizationUnits

When specifying both IncludeOrganizationUnits and ExcludeOrganizationUnits, the result is IncludeOrganizationUnits minus ExcludeOrganizationUnits.

Additional services

List of possible Targets and Event Types

To see what targets EVA supports, call GetEnumValues for EventExportTarget:

As for the event types, the list we would have to create would be immense. So if you want to take a look at the kind of event types available, call GetEventExportTargetTypes with one of your preferred targets. List calls are available to some target types as well, such as ListCashDeposits.

Examples

To give you a sense of the kind of information included in various events, we've got some basic examples lined up.

If there's an IsSystemGenerated property, it indicates whether or not the order is an order generated by EVA to mirror an existing sales or purchase order in POSO or SOPO flows.

{
"UID": "b107a139-c641-479c-a164-d333f3d414e7",
"CreationTime": "2021-08-25T16:03:54.777Z",
"TimeZone": null,
"Target": "Order",
"EventType": "created",
"Identifier": "62",
"BackendID": null,
"BackendSystemID": null,
"Region": "euw",
"Data": {
"IsSystemGenerated": false
},
"Attempt": 1
}

Stock event flow deep dive

In most cases, the basic examples here above are enough to show you what an event looks like.

Because we're feeling particularly masochistic however, here's an entire flow - consisting of 19 events - which shows what happens from the creation of a PO to its receipt in the store.

For some additional context, in this situation we started out with two kinds of products, but only received one of the two while completing the receipt/order. This way the flow also displays some cancellation events.


{
"UID":"155c86d3-6f1d-41cc-b9a1-de06a2ea8cb3",
"CreationTime":"2023-03-24T08:23:50.1393393Z",
"TimeZone": null,
"Target":"Order",
"EventType":"created",
"Identifier":1322,
"BackendID":"EventEx2",
"BackendSystemID":null,
"Region":"euw",
"Data":{
"IsSystemGenerated":"false"
},
"Attempt":1
}

Endpoint requirements

  • Your endpoint needs to respond with 200 (OK) response, with a string body [ACK]. If this is not the case, the event will retry.
  • Make sure Endpoint (or any intermediate redirect routes) does not resolve to any RFC1918 (in other words: local) addresses.
  • Make sure Endpoint uses the HTTPS protocol which is as up to date as possible - preferrably HTTP/3
  • Endpoint should be accessible from EVA
  • Webhook should accept a POST request on endpoint
  • Implement authentication on the endpoint - use preferably both the aforementioned authorization and verification

Verifying the signature

Each request to Endpoint will have the following headers:

  • X-EVA-Signing-1
  • X-EVA-Signing-2
  • X-Eva-Signing-Headers.

The latter will contain a comma separated list of all request headers considered in the signing process. This is helpful when operating behind a reverse proxy that might add some headers. Make sure this proxy does not remove any headers, as this will render you unable to validate the requests.

To validate the requests, take the following three steps.

1. Hashing the headers

Only use the headers as specified in X-Eva-Signing-Headers


Transform the headers from this:

Content-Type: application/json;charset=utf-8
Content-Length: 12345
Authentication: Bearer MySecretToken

to:

Authentication=Bearer MySecretToken
Content-Length=12345
Content-Type=application/json;charset=utf-8

Sort the headers, first by header key, then by header value
Next make sure the header key and value are separated by a =
Also make sure the line breaks are \n

Then we transform this text to bytes (use UTF-8) and hash it using SHA256. Save the hash as a uppercase hexadecimal string.


2. Hashing the body

Hash the body using SHA256. Save the hash as a uppercase hexadecimal string.


3. Calculate the hash

Calculate the final hash as follows (store as uppercase hexadecimal string):

final_hash = sha256(header_hash + body_hash + api_key)

This hash should match either X-EVA-Signing-1 or X-EVA-Signing-2.

Testing, queues and errors

Testing event exports is extremely easy. Make sure you have an endpoint for testing and make sure your settings are correct. Don't have an endpoint for testing? We advise Hookbin. Now just use one of our frontends (or services) to mutate stock, place an order or anything else, and check your endpoint for the exported events.

Queuing

As mentioned throughout this document, your endpoint needs to respond with a 200 (OK) message. If it doesn't, the event is seen as failed and EVA will retry - at least up to a certain point. The way EVA handles this also differs per type of environment.

Failed

When an export fails on a PRODUCTION environment, EVA will try again based on exponential backoff: the message will be sent again after 5 seconds, 10 seconds, 20 seconds, etc. up to 24 hours. After this, you can no longer reach the message.

On TEST environments however, where are endpoints are often used liberally, EVA automatically disables your endpoint after either 200 failed messages, or 30 minutes of consecutive error messages. In this case the endpoint will get Status Error (3), but you can simply set it to Status Enabled (1) again if necessary.

Endpoint disabled

This failing/retrying is different from having a disabled endpoint. If you manually disable the endpoint on PRODUCTION, a different kind of queue will automatically start. All your messages will be saved up for you until either the size of the queued messages reaches 20gb, or up to 7 days - whichever comes first.

Scripting Event exports

To customize exports based on filters, check the extension point EventExport.