# Open Banking Webhook Management System (OBWMS)
source: https://developer.mastercard.com/open-finance-us/documentation/webhooks/obwms/index.md

Webhooks allow you to receive real-time notifications when specific events occur, eliminating the need for constant polling. They are ideal for staying informed about customer activity, transaction updates, and other time-sensitive events.

* [Overview of OBWMS](https://developer.mastercard.com/open-finance-us/documentation/webhooks/obwms/index.md#overview-of-obwms)
* [Getting Started](https://developer.mastercard.com/open-finance-us/documentation/webhooks/obwms/index.md#getting-started)
* [Webhook Structure](https://developer.mastercard.com/open-finance-us/documentation/webhooks/obwms/index.md#webhook-structure)
* [Message Verification](https://developer.mastercard.com/open-finance-us/documentation/webhooks/obwms/index.md#message-verification)
* [Delivery Considerations](https://developer.mastercard.com/open-finance-us/documentation/webhooks/obwms/index.md#delivery-considerations)

## Overview of OBWMS {#overview-of-obwms}

The Open Banking Webhook Management System (OBWMS) is a new standard for managing webhook subscriptions in Mastercard Open Finance. It provides a unified, consistent approach to creating and managing webhook subscriptions. Over time, all Mastercard Open Finance webhooks will conform to this standard. Currently, only a subset of webhooks use OBWMS.

OBWMS will provide a comprehensive API for managing real-time event notifications, enabling you to subscribe to specific events, ensuring you only receive relevant updates.
Warning: The endpoints for subscribing to and testing webhooks via OBWMS are being developed as a standalone service, not tied to US Open Finance.

Documentation for these endpoints will be provided soon. In the meantime, the information presented here is meant to provide an overview of how OBWMS subscriptions work.

For details of the specific events that are available for subscription, refer to the documentation for each Open Finance product that uses OBWMS.

## Getting Started {#getting-started}

### Obtaining a Mastercard Signature Verification Key {#obtaining-a-mastercard-signature-verification-key}

Before creating webhook subscriptions, you need to ensure you have added a **Mastercard signature verification key** to your project in your project dashboard on Mastercard Developers. This key is required to authenticate and validate webhook messages.

See the [API Basics](https://developer.mastercard.com/open-finance-us/documentation/onboarding/index.md#authentication) documentation for more details of how to create all the necessary credentials and [keys](https://developer.mastercard.com/open-finance-us/documentation/onboarding/index.md#obwms-authentication) when working with your project. If you don't have a Mastercard signature verification key, make sure you add one and download it.

![](https://static.developer.mastercard.com/content/open-finance-us/uploads/create-sig-key-obwms-openfinance.png)

### Setting up a Listener {#setting-up-a-listener}

To receive OBWMS webhook events, you must provide an HTTPS endpoint capable of accepting **HTTP POST** requests. Your listener should be lightweight, resilient, and able to acknowledge receipt quickly. You pass this endpoint URL when creating a webhook subscription.
Tip: For testing purposes, you can use tools like webhook.site or beeceptor.com that receive webhooks and post the content for you to review (note that this is not an official endorsement of any of these services). In production, you **must** use your own secure webhook service.

#### Listener Best Practices {#listener-best-practices}

* **Respond immediately with a 2xx status**
  Your endpoint should return HTTP 200 or 204 immediately upon receipt, before performing signature verification or other processing. Responding early ensures OBWMS does not retry unnecessarily.

* **Avoid detailed error responses**
  If the payload is malformed or unexpected, log the issue internally but do not return detailed error information.

* **Avoid redirects**
  Any 3xx response (including 307 or 308) is treated as a failure and retried. Ensure the listener URL resolves directly to an endpoint that can process the webhook.

* [Additional Tips and Best Practices for Receiving Webhooks](https://developer.mastercard.com/open-finance-us/documentation/webhooks/obwms/index.md#additional-tips-and-best-practices-for-receiving-webhooks)

### Creating a Subscription {#creating-a-subscription}

To receive webhook events, you must create a subscription, in which you specify the details of the events they would like to receive and the endpoint it should be sent to.

A new subscription API is currently under development. For subscription support, please reach out to your account representative.

## Webhook Structure {#webhook-structure}

### Message Headers {#message-headers}

OBWMS event messages include the following message headers:

**Content-Type:** Indicates the format of the data within the webhook body. This is always set to "application/json".

**X-Mastercard-Signature:** This header contains a unique hash of the webhook payload. Uniqueness is provided by combining the message payload with the timestamp of signature generation. See [Verifying the Message Signature](https://developer.mastercard.com/open-finance-us/documentation/webhooks/obwms/index.md#verifying-the-message-signature) for more information.

**X-Mastercard-Signature-Timestamp:** This header indicates the time, in milliseconds, of when the signature was calculated. This is used to help prevent replay attacks.

**X-Mastercard-Signature-Algorithm:** This header indicates the hashing algorithm used for generating the message hash for the webhook. Currently, this service only supports "SHA256withECDSA."

**X-Mastercard-Signature-Version:** This header indicates which version to use when calculating the message signature. This header is provided for forward-compatibility as new algorithms are added.

**X-Mastercard-Webhook-Message-Id:** A unique identifier (UUID) for each webhook event/message. This identifier remains the same across retry attempts, allowing consumers to reliably detect and handle duplicate deliveries.

**X-Mastercard-Signature-Verification-Key:** The unique fingerprint of the signature key used when calculating the value of the X-Mastercard-Signature header. If multiple signing keys have been registered for use within the webhook system, this header is essential for determining which signing key is being used.
Tip: When received, HTTP headers may be presented as lowercase strings. The above documentation is capitalized for readability.

### Message Body {#message-body}

The body of the webhook event contains the data generated by the webhook, as a string. The receiving application is responsible for reading the Content-Type HTTP header and parsing the webhook data accordingly.

Each webhook event type contains its own unique structure. Consult the documentation for the desired webhook event for more information regarding its particular structure.

The webhook structure is based on the CloudEvents 1.0 specification. When receiving a webhook, you can expect these standard fields to be provided at the beginning of each webhook message:

|    Event field    |       Type       |                                                                                                        Description                                                                                                        |
|-------------------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id`              | string           | Identifies the event. This is unique for each distinct event. If an event with the same ID is received, you can assume it is a duplicate (for example, an event could potentially be re-sent because of a network issue). |
| `time`            | RFC 3339         | Timestamp of the event.                                                                                                                                                                                                   |
| `type`            | string           | The type of event.                                                                                                                                                                                                        |
| `source`          | string           | This is the Mastercard OBWMS, which is `openfinance.mastercard`.                                                                                                                                                          |
| `specversion`     | string           | The CloudEvents specification version that the message complies with.                                                                                                                                                     |
| `datacontenttype` | application/json | Media type for the event payload.                                                                                                                                                                                         |
| `subscriberid`    | string           | The ID of the partner subscribing to the event (in other words, your partner ID).                                                                                                                                         |
| `correlationid`   | string           | An optional attribute for correlating this event with related events, requests, or workflows. This can be useful for end-to-end tracing, business process correlation, or tracking request lineage.                       |

Individual services then append their own specific message data relating to the particular event concerned.

## Message Verification {#message-verification}

Several steps should be taken when verifying webhooks received. Firstly, the `X-Mastercard-Webhook-Message-Id` header may be checked against a list of previously received webhooks to guard against replay attacks.

### Verifying the Message Signature {#verifying-the-message-signature}

To verify the identity of the sender (Mastercard), it is important that the receiving application perform a hashing of the webhook body, concatenated with the value of `X-Mastercard-Signature-Timestamp`, and comparing it to the value of `X-Mastercard-Signature`. The value of `X-Mastercard-Signature-Algorithm` indicates which algorithm to use when generating the message hash. In pseudo-code, this can be expressed as:

    messageHash = hashingFunction(webhook-message + "." + webhook-timestamp)

The default signature verification key is generated using SHA256 with ECDSA and the public key can be downloaded via the Mastercard Developer Portal.

![](https://static.developer.mastercard.com/content/open-finance-us/uploads/view-sig-key-openfinance.png)

With that information, the following code snippet is an example of how message verification may be performed.

```js
// Nodejs
const crypto = require('node:crypto');

const HASH_ALGORITHM = 'sha256';
// Loaded at startup, or selected based on X-Mastercard-Signature-Verification-Key header
const PUBLIC_KEY = process.env.PUBLIC_KEY;

/**
 * @param {string} signature - Provided via X-Mastercard-Signature header
 * @param {string} webhookMessage - Webhook body
 * @param {number} timestamp - Provided via X-Mastercard-Signature-Timestamp
 * @returns {boolean}
 */
function isValidWebhook(signature, webhookMessage, timestamp) {
  const verify = crypto.createVerify(HASH_ALGORITHM);
  verify.write(`${webhookMessage}.${timestamp}`);
  verify.end();
  return verify.verify(PUBLIC_KEY, signature, 'hex');
}
```

### Verifying Timestamps {#verifying-timestamps}

The threshold for valid timestamps is determined by the receiving application. To mitigate replay attacks, you should validate webhook timestamps and discard those with unreasonably old timestamps.

## Delivery Considerations {#delivery-considerations}

All webhook requests are sent using HTTP POST. The application receiving the webhook is expected to respond within 30 seconds with an HTTP 200 or 204 to indicate successful receipt of the webhook. All other HTTP status codes are considered errors and the message is re-queued for delivery. Importantly, any status code indicating a redirection (for example, HTTP 307 or 308) is rejected and re-queued.

### Message Retry {#message-retry}

Failed messages are retried over a 24-hour period using an exponential backoff.

The following table describes the retry intervals under near ideal conditions, that is, no network latency and optimal webhook service settings.

| Retry Delivery Attempt | Next attempt after | Interval until next attempt |
|------------------------|--------------------|-----------------------------|
| 1                      | 6 seconds          | 42 seconds                  |
| 2                      | 48 seconds         | 4 minutes 30 seconds        |
| 3                      | 5 minutes          | 29 minutes 8 seconds        |
| 4                      | 34 minutes         | 3 hours 8 seconds           |
| 5                      | 3 hours 42 minutes | 20 hours 17 seconds         |
| 6                      | 24 hours           | -                           |

### Additional Tips and Best Practices for Receiving Webhooks {#additional-tips-and-best-practices-for-receiving-webhooks}

#### Close Connections Early {#close-connections-early}

Webhooks can create spikes in HTTP calls to receiving applications. If not handled properly, these spikes can exhaust available TCP sockets, creating bottlenecks on the network. We recommended that the receiving application respond to the webhook message (with an HTTP 200, 202, or 204 response) *immediately upon receipt*, before any processing is performed on the webhook payload (this includes signature validation).

#### Fail Silently {#fail-silently}

A key in reducing abuse to endpoints exposed for webhooks is to remove any unnecessary response information. In the case of webhooks, the sender only needs to know if the payload was received, not if the data was processable. Returning status codes such as HTTP 400 when a webhook does not follow an expected format does not provide any actionable information to legitimate webhook senders but allows a potential attacker to further refine their attacks. Any errors, such as unexpected payloads, should be logged but not returned on endpoints designed to receive webhooks.

In cases where the receiving application is under heavy load and cannot process more requests, it is advised that the application return a 4xx error code, such as HTTP 429 Too Many Requests, which causes the webhook sender to reschedule the webhook for a later time. See the above chart for information regarding the retry intervals.

#### Queue Messages Internally {#queue-messages-internally}

In cases where a large volume of webhooks is expected, it may be desirable to queue received messages for process using something like RabbitMQ. This can reduce the chance of webhooks failing to be received as servers become congested with webhook traffic. If queueing is to be used, it is advised that all webhook messages are verified before being placed into the queue to prevent invalid or malicious webhook payloads accidentally being processed.

#### Check for Expected Algorithms {#check-for-expected-algorithms}

The information provided via the webhook headers should be treated as informational only. Information such as the algorithm being used should be compared against an expected list prior to processing the webhook and should never be used directly.

```js
// Bad
const verify = crypto.createVerify(headers['X-Mastercard-Signature-Algorithm']);

// Good
if (headers['X-Mastercard-Signature-Algorithm'] === 'SHA256withECDSA') {
  const verify = crypto.createVerify('SHA256withECDSA');
}
```

