Creating and Managing Destinations

In the Integrations section of the Console, you can create Destinations for your integrations to link to:

  • Currently, only webhooks can be designated as the endpoint for an integration:

    • If you've defined a Notification Rule based on a system event, you can link this to a webhook integration Destination as the endpoint for the Notification. See Utilizing Events and Notifications for more details.

  • You can specify the type of authentication you want an integration to use when connecting to the Destination:

    • Currently, only the M3TER_SIGNED_REQUEST credentials format can be used as the authentication method used for connecting to a webhook Destination. See the Webhook Authentication section below for more details on how to work with this format.

    • If credentials are not required, then dummy values can be used.

When you have created a Destination, you can link an integration or Notification to it and complete your setup.

Tip: Integrations Webhook API Example? See Integrations Webhook API Example in our API Reference for a worked example of creating a webhook destination using the API.

This topic explains how to create and manage your integration Destinations. Detailed guidance is also given on how to construct and verify a secure signature for the M3TER_SIGNED_REQUEST:

Creating Destinations

To create a Destination:

1. Select Integrations>Destinations. The Destinations page opens and lists any existing Destinations.

2. Select Create destination. The Create page opens.

3. Enter Destination Details:

  • Name and Code:

    • Note that when you enter a name and click in the Code field, a default code is entered based on the name you've entered, which you can then edit as required.

  • Description for the Destination.

  • URL for the webhook Destination.

Important - only valid Domain Name System (DNS) entries permitted! If you enter an invalid DNS entry for the webhook destination URL, then an error message will show when you try to save the Destination.

4. In the Credentials panel:

  • Select the Credential Type you want to use for authentication with the Destination:

    • Note that only the M3TER_SIGNED_REQUEST authentication method is currently available.

  • Enter the API key and API secret you want use for the M3TER_SIGNED_REQUEST authentication when connecting to the Destination.

5. Select Create Destination. You are returned to the Destinations Details page. The Destination is now available for linking your integrations or Notifications to it.

Managing Destinations

From the Destinations page, you can edit, view details, or delete a Destination.

To manage Destinations:

1. Select Integration>Destinations. The Destinations page opens and lists any existing Destinations.

2. If you want to edit a Destination select Edit:

3. On the Edit page, make your changes and select Update.

4. If you want to view the details of a Destination, select its NAME hotlink. The Destination Details page opens:

In this example, Notification Destination 1 details are shown. Note that you can Copy directly to your Clipboard certain key attributes:

  • URL

  • Destination id

  • API key

  • ID

5. If you want to delete a Destination, select Delete:

A confirmation dialog appears. Select Yes to confirm the delete action.

Warning! If you try to delete a Destination to which you've linked an integration or Notification, then you won't be able to and an error message will show.

Webhook Authentication for M3TER_SIGNED_REQUEST

Currently, the only authentication support for connecting to a webhook is signing a request using an ApiKey and ApiSecret. In m3ter, this is the M3TER_SIGNED_REQUEST credentials format. This format implements a signed request for webhook access and is designed to enable you to build secure webhook endpoints and safeguard them from malicious attacks.

m3ter will sign all the requests it makes to your webhook. When you receive a request on your configured endpoint, you should:

  • Validate that the timestamp of the request is within an acceptable grace period.

  • Compute the signature based on the information you receive and compare that with the signature m3ter passes. This allows you to verify that the request was made by m3ter and not a third party as bad actor.

You'll receive the following m3ter headers:

  • X-m3ter-timestamp - the timestamp when m3ter made the request.

  • X-m3ter-apikey - the apiKey corresponding to the apiSecret used to sign the request.

  • X-m3ter-signature - the signature m3ter computed for this request. You need to validate this header.

  • X-m3ter-signaturemethod - the algorithm used for computing the signature. Currently, the algorithm used is always HmacSHA256.

  • X-m3ter-version - the m3ter signature algorithm. Currently, this is always 1.

Validating the X-m3ter-signature Header

To validate the X-m3ter-signature header, you must prepare a payload String that you sign with your API Secret.

To compute the payload, you must concatenate the following data using a pipe | separator:

  • url

  • query string - Currently, there's no support for passing in query parameters. For now, you can hard code to this String: {}

  • API Key - provided in the X-m3ter-apikey header.

  • timestamp -provided in the X-m3ter-timestamp header.

  • body - the request body.


X-m3ter-timestamp: 1688460685310
X-m3ter-apikey: testApiKey
X-m3ter-signature: a9f9936e662512f943a904f3a71d0141c9bdfbf9fd5496902172864e9333ba15
X-m3ter-signaturemethod: HmacSHA256
X-m3ter-version: 1
body: {"orgId":"f49e8e22-ddd2-4367-b1ed-761e7e1fbdfd","entityId":"136f7b01-6bbd-4779-88a1-4a22d47b4f97","requestType":"NOTIFICATION","name":"Bill Approved for Locking","description":"Bill approved for locking","accountId":"16c14570-5790-43b5-9ed8-109541b780bb","originalEventId":"8ab97599-02a4-4604-b9fb-e0110ef3dbb9","eventName":"billing.bill.updated","notificationEventId":"679c70ef-f843-4dac-add2-75420666f598","notificationCode":"bill_approved_for_locking"}

The payload will be:

payload = "|{}|testApiKey|1688460685310|{\"orgId\":\"f49e8e22-ddd2-4367-b1ed-761e7e1fbdfd\",\"entityId\":\"136f7b01-6bbd-4779-88a1-4a22d47b4f97\",\"requestType\":\"NOTIFICATION\",\"name\":\"Bill Approved for Locking\",\"description\":\"Bill approved for locking\",\"accountId\":\"16c14570-5790-43b5-9ed8-109541b780bb\",\"originalEventId\":\"8ab97599-02a4-4604-b9fb-e0110ef3dbb9\",\"eventName\":\"billing.bill.updated\",\"notificationEventId\":\"679c70ef-f843-4dac-add2-75420666f598\",\"notificationCode\":\"bill_approved_for_locking\"}"

Nodejs Example

const crypto = require('crypto');
// Main function to validate request authenticity
exports.validateSecret = function({ url, queryString, apiKey, apiSecret, timestamp, body, signature }) {
var currentTimestamp =;
var result = false;
// Check if the provided timestamp is in the past by comparing it with the current timestamp
if (currentTimestamp - 30 * 1000 > timestamp) {
var details = "timestamp in the past: " + currentTimestamp;
return {"result": result, "log": details};
// Prepare the payload string by concatenating the request data
var sharedSecret = apiSecret; // Secret associated with the apiKey
var safeQueryString = !queryString ? '{}' : queryString;
var payload = url + "|" + safeQueryString + "|" + apiKey + "|" + timestamp + "|" + JSON.stringify(body);
// Generate a cryptographic signature of the payload using HMAC-SHA256
var sig = crypto.createHmac('sha256', sharedSecret)
// Compare the generated signature with the provided signature using a timing-safe comparison
result = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(signature));
// Return the result and additional information for debugging
return {"result": result, "log": {"payload": payload, "sig": sig, "signature": signature}};

Next: Managing Integration Credentials

Additional Support

Login to the Support portal for additional help and to send questions to our Support team.