Subscriptions
Subscriptions are a mechanism that allows consumers to receive regular updates or notifications about specific services or applications. Subscription notifications are messages or alerts sent to users who have subscribed to a particular service or product. They enable you to receive relevant events via push notifications in real-time. By subscribing to events of your interest, you can ensure that you stay informed and promptly receive updates when these events occur.
|
Subscriptions that are not working correctly for an extended period of time, will be automatically disabled. You can re-enable the subscription yourself via the Update Event Notification Subscription endpoint. The conditions under which we disable subscriptions are as follows:
For all the above scenarios, we will retry delivery 10 times over a period of 10 minutes. Should the destination of the subscription be unreachable for that time frame, we will automatically disable the subscription. |
How can they help?
Subscribing to relevant events can enhance the functionality and user experience of your applications significantly benefiting you in the following ways.
Subscriptions helps you in:
-
Receiving near real-time updates ensuring that your application data and user interfaces are up-to-date.
-
Retrieving data efficiently thereby reducing the unnecessary data requests and optimizing the resource usage.
-
Simplified integration by reducing the complexity of handling data updates.
-
Scalability of applications by handling events asynchronously, leading to better performance and responsiveness.
Delivering subscription notifications
Choose the delivery channel that fits your infrastructure before configuring a subscription.
Subscriptions are delivered to users through the following communication channels, depending on the nature of the subscription and user preferences.
The delivery methods for subscription notifications include:
-
Webhooks - Signifies an endpoint on the user’s side that receives a message whenever a subscribed event takes place.
-
Google Cloud Platform (GCP) Pub/Sub - Enables the asynchronous queuing of messages on the partners' own GCP project, providing a safer, more efficient and reliable solution compared to webhooks.
Hosting Pub/Sub topics may incur additional costs. -
Amazon Web Services (AWS) SQS - Like Pub/Sub above, SQS enables asynchronous queuing of notifications on the partner’s AWS project, providing an integrated, secure, efficient and reliable solution.
Supported event types
Choose which events you want to subscribe to based on your use case.
For details on all available event types and their supported delivery methods, see Supported event types.
Configuring subscriptions
Set up your chosen delivery channel to start receiving notifications.
For setup instructions for Webhooks, GCP Pub/Sub, and AWS SQS, see Configuring subscriptions.
Subscriptions API endpoints
Use these endpoints to create and manage your subscriptions via the API.
The Subscriptions API offers the following endpoints:
Subscription service features
Understand the delivery behaviour you need to account for in your implementation.
The subscription service offers the following features:
-
At-least-once delivery - To ensure maximum reliability, we implement at-least-once message delivery. As a result, there is a possibility of receiving the same message multiple times.
Ensure that your system is equipped to accommodate such scenarios. To facilitate this, one approach is to maintain a record of processed messages on your side. This would allow you to track and avoid reprocessing duplicate messages, ensuring the efficiency of your system.
-
Retry mechanism - In cases where the first delivery attempt of the message fails, the system will initiate nine subsequent retries with an increasing accumulated interval between each retry. This strategy aims to improve the chances of successful message delivery. This mechanism is also known as "exponential backoff".
|
If the message still remains undelivered after 10 retries, no further delivery attempts will be made and the message will be dropped. As an alternative approach, you can always use the respective GET endpoints provided by the Retailer API for retrieving the required information as a fallback scenario. |
-
Possible race conditions - There is a possibility of messages arriving in the incorrect order.
For instance, consider the scenario where Message A and Message B, both associated to the same process, encounter failures during delivery. The retries for Message A failed twice, while the retry for Message B failed once.
Later, assuming that your system becomes operational during this time, Message B may be retried after 2 minutes, while Message A will be sent after 4 minutes.
To facilitate verification of such situations, a timestamp is included in the message. This allows you to track and assess the timing of message deliveries.
The timestamp in the message represents the time the event was created, not the time the notification was sent.
Request signing
All messages sent from bol, regardless of delivery method, can be verified using digital signatures. This allows you to ensure that the messages were not tampered with through means such as man-in-the-middle attacks, and prevents abuses of your public endpoints by third parties flooding your endpoints with bad requests.
A signature is added to every outgoing message by signing the request body with a public/private keyset. The private key is used by bol for creating the signature, while the public key is used by the partner for verification. Depending on the delivery method, the signature is made available as follows:
-
Webhooks — delivered as an HTTP
Signaturerequest header. -
GCP Pub/Sub — delivered as a Pub/Sub message attribute named
Signature. -
AWS SQS — delivered as an SQS message attribute named
Signature.
You can use the public keys retrieved from the bol API to verify the signature, after which you can commence with your transactions.
Signature header structure
An example of the signature header sent to you is provided below:
Signature: keyId=0, algorithm="rsa-sha256", signature=<SIG>
The three elements in the signature are:
-
keyId- Specifies the ID for the keyset that is used to create the signature. We have built a method to create new keysets once the old ones become compromised through getting leaked or hacked. -
Algorithm- Specifies the algorithm used to create the signature. In our case we use a static value ofrsa-sha256. For more information see RSA-SHA256 signatures. -
Signature- Specifies the created signature that can be verified by the recipient of the message. The signature is sent as a Base64 encoded UTF-8 string. Depending on the library doing the verification, the signature might need to be Base64 decoded before it is validated.
Retrieving public keys from the Subscription API
The keys referenced in the signature are available from the Subscription API.
For more information on how to retrieve them, see Retrieving public keys for signature validation.
Validating the signature
The SHA256 algorithm calculates a unique hash of the input data, then encrypts the hash with the private key. To verify the authenticity of the message, you should:
-
Calculate a hash of the same data using the public key.
-
Decode the hash from Base64 using the public key and load it as an X.509-spec key.
-
Compare the hash values. If they match, the signature is considered valid. If they don’t match, it either means that a different key was used to sign it, or that the data has been altered.
The following code sample validates the signature of a request to use as a baseline for the implementation - you can adapt it to your programming language of choice. No additional libraries beyond the standard JVM are required:
String subscriptionKey = "PUBLIC_KEY_STRING_RETRIEVED_FROM_SUBSCRIPTION_ENDPOINT";
// Retrieve the key from merchant, decode it with the Base64 decoder.
byte[] encodedKey = Base64.getDecoder().decode(subscriptionKey.getBytes(StandardCharsets.UTF_8));
// Load the public key, use the SHA256withRSA instance and load it as an X509KeySpec
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(encodedKey));
// Given the following extracted signature from the request header
String signature = "SIGNATURE_FROM_PUSH_NOTIFICATION_HEADER";
// And the message body sent to the push notification endpoint
String body = "Message body";
// Decode the signature and convert it to a byte array
byte[] signatureBytes = Base64.getDecoder().decode(signature.getBytes(StandardCharsets.UTF_8));
// Verify the signature using the public key created earlier
final Signature sha256RsaSignature = Signature.getInstance("SHA256withRSA");
// Initialize the signature with the publickey
sha256RsaSignature.initVerify(publicKey);
// Add the bytes string conversion of the signature header
sha256RsaSignature.update(body.getBytes(StandardCharsets.UTF_8));
// Verify the signature, this function will return true for valid signatures
boolean result = sha256RsaSignature.verify(signatureBytes);
The following code sample is the Kotlin equivalent. No additional libraries beyond the standard JVM are required:
val subscriptionKey = "PUBLIC_KEY_STRING_RETRIEVED_FROM_SUBSCRIPTION_ENDPOINT"
// Retrieve the key from merchant, decode it with the Base64 decoder.
val encodedKey = Base64.getDecoder().decode(subscriptionKey.toByteArray(Charsets.UTF_8))
// Load the public key, use the SHA256withRSA instance and load it as an X509KeySpec
val publicKey = KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(encodedKey))
// Given the following extracted signature from the request header
val signature = "SIGNATURE_FROM_PUSH_NOTIFICATION_HEADER"
// And the message body sent to the push notification endpoint
val body = "Message body"
// Decode the signature and convert it to a byte array
val signatureBytes = Base64.getDecoder().decode(signature.toByteArray(Charsets.UTF_8))
// Verify the signature using the public key created earlier
val sha256RsaSignature = Signature.getInstance("SHA256withRSA")
// Initialize the signature with the publickey
sha256RsaSignature.initVerify(publicKey)
// Add the bytes string conversion of the signature header
sha256RsaSignature.update(body.toByteArray(Charsets.UTF_8))
// Verify the signature, this function will return true for valid signatures
val result = sha256RsaSignature.verify(signatureBytes)
IP Whitelisting
These are the public IP addresses from which we publish messages that you can whitelist if needed. Although this list is static, it is not guaranteed that these IP addresses remain the same over time. IP addresses can either be removed or added to this list.
35.204.245.136
35.204.195.116
35.204.156.102
35.204.83.251
35.204.231.62
34.90.203.104
34.90.109.47
34.91.34.58
34.91.134.228
34.91.91.54
Automatic subscription disabling
In the event that our system fails to contact your subscription destination (due to an outage on your end, invalid configuration, or missing permissions in the case of Pub/Sub), we will automatically disable the subscription. This will happen after ten failed attempts.
The subscription may be re-activated by updating it and setting the enabled flag to true. Note that this change might take up to 15 minutes to propagate.
Once a subscription is deactivated, messages will no longer be sent. If the subscription is reactivated, previously unsent messages cannot be resent.