Skip to main content
Skip table of contents

IMOS - Webhooks

Home > Overview > Webhooks


Overview

Webhooks in the Veson IMOS Platform are a tool for generating real-time feedback and providing suggested changes to users as they work in the Voyage Estimator. Like Tasks & Alerts, messages are generated and displayed in the notifications panel based on logical rules applied to the current data. Unlike standard Tasks & Alerts, webhooks allow you to write whatever logic you choose in a programming language of your choice, as long as you can host it as a web endpoint. The response payload may also include suggested changes that can be automatically applied to the estimate itself.

Setting up a webhook in the Tasks & Alerts form

To set up a webhook, go to the Tasks & Alerts Rule Set List in the Data Center module and create a new Rule Set that applies to the Voyage or Voyage Estimate. In the Edit Rules form, select the Use Webhook checkbox.

Screenshot of the Task and Alert edit rules form showing the Use Webhook checkbox

In the Data fields to include window, select the fields that you will want to be sent to your webhook endpoint. To add more fields, click the “Add Field” link below the field list. To add multiple fields at a sub-object level (eg., more Port fields), use the '…' menu to the right.

Set the Webhook URL to your webhook endpoint. If your webhook needs to validate the sender, enter or generate an API key (recommend 32-64 random ASCII characters).

IMOS Config flag values can also be sent along in the header of a webhook request. This can be useful for integration with other 3rd party APIs, such as those that require access tokens on a client-by-client basis.

When finished, select Update Rule Set, then save the rule set.

If you only want to run a webhook conditionally, you can use the “stop processing if true” feature of Tasks & Alerts. Create a non-webhook rule that has the condition before the webhook rule in the same rule set.

Running your webhook

To run your webhook, navigate to Estimates in the Chartering module and open an estimate in details view. Then, expand the Notifications panel. In this panel, you will see the response message that is returned by the webhook.

The Notifications panel, will display all Webhook Responses and Tasks & Alert results in card view when the CFGEnableAgGridInNotificationsPanel flag is enabled.

The cards will be split into different sections based on the type of rule they are generated from (Tasks, Alerts, or Webhooks). These sections can be expanded/collapsed by clicking on the down/up caret at the top of each section and can be rearranged so that the highest priority items are present at the top of the panel.

You can also access notifications in the Worksheet Estimate Column by selecting the double arrow icon >> to expand the Notifications panel for that Estimate, including Tasks, Alerts, and Webhooks.

Card details

The Webhook Card in the Notifications panel has a standard structure to it:

Webhook Card in the Notifications panel

The name of the Rule from the Rule Set will be displayed in bold at the top of the card, followed by any text that is sent back in the response payload.

If the response includes a link, then the card will display a Source Link button that will redirect to the link provided. This is useful when the webhook response might require further investigation by the user.

If the response includes a mutation, then the Apply to Estimate button will be displayed in the card. The user can click on this button which will update the details in the estimate with whatever fields were sent across in the mutation.

Screenshot of the Webhooks card showing the three dot menu

Lastly, there is a three-dot menu button at the top right of the card where the user can View the Tasks & Alerts Rule that triggered the card to be generated, Apply Suggested Changes which will be present only when there is a mutation, and acts the same as the Apply to Estimate button or Show Webhook Details. Selecting Show Webhook Details will open the Webhook Details form:

Webhook details form in VIP

This form will show the technical details of what was sent to the webhook endpoint in the Request and what was returned from the webhook endpoint in the Response.

Specification

Whenever a user makes a change in Estimator, the current state of the estimate will be serialized to JSON and POSTed to each configured webhook endpoint. The configured endpoints must use HTTPS and provide a certificate trusted by a common root CA. The response payload must be returned in less than 10 seconds, and the content length must be less than 1MB.

Authentication

If an API key is specified in the webhook configuration, a Veson-Webhook-Signature header is included with each HTTP POST request. The value of the header is the HMACSHA256 signature of the request body (as UTF8 Bytes) with the API key string (as UTF8 bytes) as the key.

Example signature verification code
CODE
using System.Security.Cryptography;
using System.Text;

/// Utility functions
private static bool ValidateSignature(string requestContent, string signature)
{
    const string VESON_API_KEY = "hYFYXEZA36?15KMA]8hrx0FZtEfgXK1:";
    var contentBytes = Encoding.UTF8.GetBytes(requestContent);
    var apiKeyBytes = Encoding.UTF8.GetBytes(VESON_API_KEY);
    var signatureBytes = new HMACSHA256(apiKeyBytes).ComputeHash(contentBytes);

    return BytesToHex(signatureBytes) == signature;
}

private static string BytesToHex(byte[] key)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < key.Length; ++i)
    {
        sb.Append(String.Format("{0:X2}", key[i]));
    }
    return sb.ToString();
}

/// Validation code
if (!ValidateSignature(requestBodyString, Headers["Veson-Webhook-Signature"])
{
// return 401 or other error code
}

Request Format

The request includes the fields configured in the webhook setup, as per the Veson IMOS Platform Reporting schema, serialized as JSON.

Example request body
CODE
{
    "estimateCargoes": [{
          "cargoShortName": "MINERALS"
    }],
    "vessel": {
        "dWT": 28521.95
    },
    "estimateItineraries": [{
        "seq": 100,
        "portExpensesBase": 0,
        "etaGmt": "2011-01-01T00:00:00",
        "port": {
            "name": "A.R.A.",
            "unCode": ""
        }
    }]
}

Response Format

The expected response is a JSON blob consisting of an array of alert objects. An alert object can have the following fields:

Field

Type

Description

message

string

The message that appears to the user. (Required)

alertType

One of: Unspecified, PermanentWarning, Error

Determines the icon that appears with the alert. (Optional)

guid

string (GUID)

An identifier for the alert. If provided, should be unique in the context of a single response. Can be used to indicate that a given alert is the “same” as one provided in a previous response. (Optional)

mutation

object

A mutation that can be applied by the user, in the same format used in the imos/applyUpdateEstimate GraphQL API (Optional)

displayFields

object

Customized field labels and values that can be displayed in the body of the card (Optional)

label

string

Field label displayed in the body of the card’s Display Fields section (Optional)

value

string

Matching value displayed with the label in the body of the card’s Display Fields section (Optional)

Link

string

A link specified by the user, presumably leading to the source of the webhook data. (Optional)

Example response body
CODE
[
  {
	"message": "Charterer for Cargo GRAIN flagged for Sanctions Activity and Low Rating. Update or reach out to the Compliance Team for Approval.",
	"alertType": "PermanentWarning",
	"mutation": {
		"estimateItineraries": {
			"speed": 13.4,
			"voyageEstimateBunkers": [
				{
					"fuelType": "LSF",
					"departureQty": 175
				},
				{
					"fuelType": "LSG",
					"departureQty": 52.85
				}
				]
		}
	},
	"displayFields": [
		{
			"label": "Client Rating",
			"value":"C"
		},
		{
			"label": "Sanctions Activity",
			"value":"True - Subsidiary"
		},
		{
			"label": "Last Reviewed",
			"value":"1st September 2022"
		}
	],
    "link": "https://www.google.com/maps"
  }
]
Mutation Schema

This is the schema as of October 2022. The most updated schema can always be found at: https://emea.veslink.com/schema/messages/UpdateEstimate

CODE
{
   "$id":"messages/#UpdateEstimate",
   "$schema":"http://json-schema.org/draft-07/schema",
   "additionalProperties":false,
   "properties":{
      "$schema":{
         "type":"string"
      },
      "to":{
         "type":"array",
         "minItems":1,
         "description":"The target company code(s) to send the message to",
         "items":{
            "type":"string",
            "description":"A target company code to send the message to"
         }
      },
      "comment":{
         "type":"string",
         "description":"Additional comment to attach to the message being sent"
      },
      "intent":{
         "type":"string",
         "const":"UpdateEstimate",
         "description":""
      },
      "data":{
         "type":"object",
         "additionalProperties":false,
         "properties":{
            "estimateID":{
               "type":"string"
            },
            "vesselCode":{
               "type":"string"
            },
            "voyageCommenceDateLocal":{
               "type":"string",
               "format":"date-time"
            },
            "estimateCargoes":{
               "type":"array",
               "items":{
                  "type":"object",
                  "additionalProperties":false,
                  "properties":{
                     "cargoSeq":{
                        "type":"number"
                     },
                     "cargoID":{
                        "type":"number"
                     },
                     "cargoShortName":{
                        "type":"string"
                     },
                     "chartererShortName":{
                        "type":"string"
                     },
                     "cpQty":{
                        "type":"number"
                     },
                     "cargoUnit":{
                        "type":"string"
                     },
                     "freightRateBase":{
                        "type":"number"
                     },
                     "curr":{
                        "type":"string"
                     },
                     "freightType":{
                        "type":"string"
                     },
                     "laycanFromLocal":{
                        "type":"string",
                        "format":"date-time"
                     },
                     "laycanToLocal":{
                        "type":"string",
                        "format":"date-time"
                     },
                     "optionPercentage":{
                        "type":"number"
                     },
                     "option":{
                        "type":"string"
                     }
                  }
               }
            },
            "estimateItineraries":{
               "type":"array",
               "items":{
                  "type":"object",
                  "additionalProperties":false,
                  "properties":{
                     "seq":{
                        "type":"number"
                     },
                     "portNo":{
                        "type":"number"
                     },
                     "cargoSeq":{
                        "type":"number"
                     },
                     "portFunction":{
                        "type":"string"
                     },
                     "loadDischargeQuantity":{
                        "type":"number"
                     },
                     "loadDischargeRate":{
                        "type":"number"
                     },
                     "rateUnit":{
                        "type":"string"
                     },
                     "portExpensesBase":{
                        "type":"number"
                     },
                     "weatherFactorPercentage":{
                        "type":"number"
                     },
                     "terms":{
                        "type":"string"
                     },
                     "idleDays":{
                        "type":"number"
                     },
                     "extraPortDays":{
                        "type":"number"
                     },
                     "extraSeaDays":{
                        "type":"number"
                     },
                     "speed":{
                        "type":"number"
                     },
                     "portDays":{
                        "type":"number"
                     },
                     "demurrageDays":{
                        "type":"number"
                     }
                  }
               }
            },
            "categoryID":{
               "type":"number"
            },
            "contractType":{
               "type":"string"
            },
            "commencePort":{
               "type":"object",
               "additionalProperties":false,
               "properties":{
                  "portNo":{
                     "type":"number"
                  },
                  "name":{
                     "type":"string"
                  }
               }
            },
            "weatherFactorPercentage":{
               "type":"number"
            },
            "dailyCost":{
               "type":"number"
            },
            "addressCommission":{
               "type":"number"
            },
            "speedBallast":{
               "type":"number"
            },
            "speedLaden":{
               "type":"number"
            },
            "terminatingPort":{
               "type":"string"
            },
            "lockProfit":{
               "type":"boolean"
            },
            "profit":{
               "type":"number"
            },
            "lockTCE":{
               "type":"boolean"
            },
            "tcE":{
               "type":"number"
            },
            "voyageEstimateBunkers":{
               "type":"array",
               "items":{
                  "type":"object",
                  "additionalProperties":false,
                  "properties":{
                     "fuelType":{
                        "type":"string"
                     },
                     "initialPrice":{
                        "type":"number"
                     }
                  }
               }
            },
            "commit":{
               "type":"boolean"
            },
            "initFromBenchmark":{
               "type":"boolean"
            },
            "atSeaBunkerPrice":{
               "type":"number"
            },
            "inPortBunkerPrice":{
               "type":"number"
            },
            "vesselImo":{
               "type":"string"
            }
         }
      }
   }
}

If you want “applied” mutations to appear as applied to the end user, include a consistent GUID (globally unique identifier) with the alert object. If no GUID or a new GUID is returned, the mutation will be interpreted as new on the front-end and displayed as such to the end users.

Regardless, reloading an estimate will reload all webhook alerts and their statuses. This is planned for future improvement.

Schema and Veson proxy documentation

https://emea.veslink.com/api/webhook-proxy/v1/docs/

Related Configuration Flags

Name/Flag

Description

Enable AG Grid in Notifications Panel
CFGEnableAgGridInNotificationsPanel

When enabled, the Notifications Panel will use an AG Grid to display the Tasks, Alerts and Webhooks in the Chartering Estimate notification panel.

Enable AG Grid in Voyage
CFGAgGridInVoyage

When enabled, the Notifications Panel will utilize AG Grid to display the Tasks, Alerts and Webhook responses within the voyage manager.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.