Webhooks
Salla's Webhooks allows you to easily set up fully automated notifications, as you get to be notified whenever your App receives payload/data from a merchant store. They are triggered when:
- A merchant installs an App
- An order or product is created in the merchant store.
- A coupon is applied, and much more
You can then use the information sent via webhooks to trigger other actions or integrate with external systems. This makes it simple to customize your notifications and keep track of all changes occurring within your Salla account.
Security Implementation
Salla secures webhook communication using headers. When an event occurs, Salla will send these headers and the relevant details to the specified App along with the token or signature verifies that the request is from Salla. Alternately, you can create a customized key and value to use with Salla's payload.
The following image illustrates how the Webhook communication is conducted in a secured vs insecured environment.
You can easily authenticate webhook calls using Salla's built-in options, which are Signature, and Token. The strategies are described in depth in the section that follows.
:::warning
Using Salla's tokens or signatures while POST
ing data, allows you to authenticate the sender. Otherwise, deny any other suspicious requests.
:::
Regsiter Webhooks
There are noticeable, interchangeable parameters in the latest Salla API update. Let us take a look at the structures in both versions as we get responses from a webhook
When sending the parameters using any endpoints from Salla, there are common properties they share, although having different structure. For more on the hows to register a webhook, check either the previous section or this API.
Parameter | Type | Description |
---|---|---|
name | string | Webhook Name |
event | string | Webhook Event From Event List |
version | number | Webhook Version; of the webhook; either valued as 1 or 2 . |
rule | string | Operations, expressions and conditions to your webhook. For example, you may use = ,!= ,AND ,OR etc in such a menner: payment_method = YOUR_PAYMENT_METHOD or in combination payment_method = mada OR price < 50 . That adds more capbility to filter the response based on conditions |
url | string | Webhook URL where you will receive the webhook calls |
headers | array[object] | Webhook headers containing security info |
headers.key | string | Any haeder key, which its value is sent in the post request to the webhook URL |
headers.value | string | The value sent to the webhook; for example: cf-ray: 669af54ecf55dfcb-FRA |
secret | string | Secret Token value |
version | string | Webhook Version; either valued as 1 or 2 . |
rule | string | Operations, expressions and conditions to your webhook. For example, you may use = ,!= ,AND ,OR etc in such a menner: payment_method = YOUR_PAYMENT_METHOD or in combination payment_method = mada OR price < 50 . That adds more capbility to filter the response based on conditions. Read more here |
:::warning
Salla currently uses API Version 2
. By default, all new registered webhooks will be set as version 2
. If you want to use version 1
of the webhook, pass that in your request parameter. Additionally, Salla will assign the Security Strategy to Signature
by default in case you registered a webhook with no security strategy defined in your body request.
:::
Security Strategies
For all created Partner Apps, Salla will assign the signature
security strategy by default, as Salla will hash payloads via an auto-generated, reproducable signature token. It will also append two headers to the webhook payload; the security startegy used as in X-Salla-Security-Strategy
which is in this context Signature
, and a hashed token signature as in 4d7dac8e688eca1c1xxxx
Security Startegy | Header | Token Suffix |
---|---|---|
Signature | X-Salla-Security-Strategy | X-Salla-Signature |
Register Endpoint
Following is the expected request payload for the Signature
security strategy:
Verify Webhooks Using Signature
Once merchants install the app in their stores, Salla uses the Siganture secret startegy (or the default one on app settings) to automatically assign webhook events.
A value for Secret must be given when establishing the webhook in order to allow webhook verification. The request body's 64 character SHA256 hash, which you may find via your partner's dashboard, will then be appended to the X-salla-signature header (e.g. x-salla-signature: ac3ea83628cccf2e98afc34223e4eeb5b41800b77737938aeed4e109f0a0xxxx
).
You can also create your own SHA256 hash of the request body using the Secret value to check the signature. Then, using a timing-safe equality function, compare the header value to your own calculated value. Here is an example of how you might accomplish this using Node.js.
const express = require("express");
const crypto = require("crypto");
const app = express();
// Base Endpoint URL: https://api.salla.dev/admin/v2
app.post('/webhooks/subscribe', (req, res) => {
const requestHMAC = req.header("x-salla-signature");
const secret = process.env.WEBHOOK_SECRET;
const computedHMAC = crypto.createHmac('sha256', secret).update(JSON.stringify(req.body)).digest('hex');
const signatureMatches = requestHMAC === computedHMAC;
if (!signatureMatches) {
res.sendStatus(401);
}
// do stuff
res.sendStatus(200);
Another demonstration can be done using the PHP language to verify a webhook header when receiving a payload. Once the webhook is received, your server can verify it from Salla in the following way:
<?php
$secret = getenv('WEBHOOK_SECRET');
$requestHMAC = $_SERVER['HTTP_X_SALLA_SIGNATURE'];
$requestBody = file_get_contents('php://input');
$computedHMAC = hash_hmac('sha256', $requestBody, $secret);
if ($requestHMAC === $computedHMAC) {
// do stuff
}
http_response_code($requestHMAC === $computedHMAC ? 200 : 401);
As of token, Salla will reserve an auto-generated, reproducable token that you can use to confirm received payloads. Two headers will be appended to your webhook response; the security startegy adapted, as in X-Salla-Security-Strategy
which is in this context Token
, and the token value itself, as in Authorization
.
Security Startegy | Header | Token Suffix |
---|---|---|
Token | X-Salla-Security-Strategy | Authorizaion |
Register Endpoint
Following is the expected request payload for the Token
security strategy:
Verify Webhooks Using Token
Once Merchants install the app in their stores, Salla assigns webhook events using the Token secret startegy. By adding a token to each event's x-salla-signature header, Salla signs the webhook events. This enables you to confirm that Salla supplied the events, and not someone else.
A value for Secret must be provided when establishing the webhook in order to allow webhook verification. The 32 character SHA256 hash of the request body, which you may acquire via your partner's dashboard, will then be appended to the X-salla-signature header (e.g. x-salla-signature: 9b8f5e05c7d107d49bd443bf2428xxxx
).
Use the Secret value to generate your own SHA256 hash of the request body to validate the token. Then, employ a timing-safe equality function to compare the value of the header with the value you computed yourself. Here is an example of how you might accomplish this using Node.js.
const express = require("express");
const crypto = require("crypto");
const app = express();
// Base Endpoint URL: https://api.salla.dev/admin/v2
app.post('/webhooks/subscribe', (req, res) => {
const requestHMAC = req.header("x-salla-signature");
const secret = process.env.WEBHOOK_SECRET;
const computedHMAC = crypto.createHmac('sha256', secret).update(JSON.stringify(req.body)).digest('hex');
const signatureMatches = requestHMAC === computedHMAC;
if (!signatureMatches) {
res.sendStatus(401);
}
// do stuff
res.sendStatus(200);
Another demonstration can be done using the PHP language to verify a webhook header when receiving a payload. Once the webhook is received, your server can verify it from Salla in the following way:
<?php
$secret = getenv('WEBHOOK_SECRET');
$requestHMAC = $_SERVER['HTTP_X_SALLA_SIGNATURE'];
$requestBody = file_get_contents('php://input');
$computedHMAC = hash_hmac('sha256', $requestBody, $secret);
if ($requestHMAC === $computedHMAC) {
// do stuff
}
http_response_code($requestHMAC === $computedHMAC ? 200 : 401);
Timeout
The timeout indicates the amount of time the client must establish the connection. Salla will wait for the HTTP response and the initiation of the connection for around 30 seconds.
:::caution
If Salla did not get a successful response from the webhook endpoint, it would trigger the webhook event three times during the event. The interval between each trial will be around five minutes. In the case of receiving a successful response, no further requests will be sent.
:::
List of Salla Store Events
Order
Name | Description |
---|---|
order.created |
This is triggered when an order has been created. |
order.updated |
This is triggered when an order has been updated. |
order.status.updated |
This is triggered when an order status has been updated. |
order.cancelled |
This is triggered when an order has been cancelled. |
order.refunded |
This is triggered when an order has been refunded. |
order.deleted |
This is triggered when an order has been deleted. |
order.products.updated |
This is triggered when an order products have been updated. |
order.payment.updated |
This is triggered when an order payment has been updated. |
order.coupon.updated |
This is triggered when an order coupon has been updated. |
order.total.price.updated |
This is triggered when an order total price has been updated. |
order.shipment.creating |
This is triggered when an order shipment is being created. |
order.shipment.created |
This is triggered when an order shipment return has been created. |
order.shipment.cancelled |
This is triggered when an order shipment return has been cancelled. |
order.shipment.return.creating |
This is triggered when an order shipment return is being created. |
order.shipment.return.created |
This is triggered when an order shipment return has been created. |
order.shipment.return.cancelled |
This is triggered when an order shipment return has been cancelled. |
order.shipping.address.updated |
This is triggered when an order shipment shipping address has been updated. |
Product
Name | Description |
---|---|
product.created |
This event is triggered when a product has been created. |
product.updated |
This event is triggered when a product has been updated. |
product.deleted |
This event is triggered when a product has been deleted. |
product.available |
This event is triggered when a product's stock has been available. |
product.quantity.low |
This event is triggered when a product's stock is of low quantity. |
Shipping Companies
Name | Description |
---|---|
shipping.zone.created |
This is triggered when a shipping zone has been created for a custom shipping company. |
shipping.zone.updated |
This is triggered when a shipping zone has been updated for a custom shipping company. |
shipping.company.created |
This is triggered when a custom shipping company has been created. |
shipping.company.updated |
This is triggered when a custom shipping company has been updated. |
shipping.company.deleted |
This is triggered when a custom shipping company has been deleted. |
Shipments
Name | Description |
---|---|
shipment.creating |
This is triggered when a shipment is assigned to a shipping company. |
shipment.created |
This is triggered when shipment is updated by the shipping company for the first time. |
shipment.cancelled |
This is triggered when a shipment is cancelled. |
shipment.updated |
This is triggered when a shipment is updated after creation. |
Customer
Name | Description |
---|---|
customer.created |
This event is triggered when a customer has been created. |
customer.updated |
This event is triggered when a customer has been updated. |
customer.login |
This event is triggered when a customer has logged in to their account. |
customer.otp.request |
This event is triggered when a customer's One-Time Password has been requested. |
Category
Name | Description |
---|---|
category.created |
This event is triggered when a category has been created. |
category.updated |
This event is triggered when a category has been updated. |
Brand
Name | Description |
---|---|
brand.created |
This event is triggered when a brand has been created. |
brand.updated |
This event is triggered when a brand has been updated. |
brand.deleted |
This event is triggered when a brand has been deleted. |
Store
Name | Description |
---|---|
store.branch.created |
This event is triggered when a store branch has been created. |
store.branch.updated |
This event is triggered when a store branch has been updated. |
store.branch.setDefault |
This event is triggered when a store branch has been set to be the default branch. |
store.branch.activated |
This event is triggered when a store branch has been activated. |
store.branch.deleted |
This event is triggered when a store branch has been deleted. |
storetax.created |
This event is triggered when a store tax has been created. |
Cart
Name | Description |
---|---|
abandoned.cart |
This event is triggered when an abandoned cart has been created. |
coupon.applied |
This event is triggered when a coupon has been applied. |
Invoice
Name | Description |
---|---|
invoice.created |
This event is triggered when the order status is either completed or restored . |
Special Offer
Name | Description |
---|---|
specialoffer.created |
This event is triggered when a special offer has been created. |
specialoffer.updated |
This event is triggered when a special offer has been updated. |
Miscellaneous
Name | Description |
---|---|
review.added |
This event is triggered when a product's review has been added. |
Troubleshooting
This section will go through why webhooks fail and what are the different scenarios you can do to troubleshoot such issues.
Why Webhook Fails
Abnormally, your webhook might not return any results after receiving a payload, and therefore Salla considers that as a failure request/response.
There are two probable explanations for why you are not receiving webhooks for your transactions:
Because the webhook URL is not specified or the transaction is not in a final state, Salla is not delivering data to your hook URL (success or failed), or
The requests are not being accepted by your webhook server.
The initial step in troubleshooting, regardless of the issue, would be to test for the situations.
Set Up Troubleshooting Environment
To troubleshoot for Salla webhooks, we will construct a workable URL from https://webhook.site/. This will act as our server, listening for Salla webhooks.
When an event occurs, the webhook data should be shown on the URL. This confirms that webhooks are being delivered to the developer/merchant's server.
Please follow the instructions below to carry out this test:
Go to https://webhook.site/
Copy the URL
Navigate to the Webhooks Tab on the store's settings page.
Create a new webhook
Name your webhook and then select the event you want to listen to
Paste the copied URL into the URL field, then save.
Now, go ahead and initiate an event. Go back to https://webhook.site/ after this event has occured on your end. You should see the webhook data for the most recent events on the webhook site.
If the webhook data is shown as in the screenshot above, it means that Salla is delivering the webhooks correctly and that the problem is most likely with your server.
:::note
You may also provide your header request parameters on the same page. Additionally, to build webhooks, you may use any API Request Builder, such as Hoppscotch or Postman.
Check out the Salla Webhooks doc page for additional information.
:::
After the Webhook environment is well-suited to start the troubleshooting, we will go through the following scenarios:
🔍 Webhook Server Troubleshooting
Following that, we'll see if your server is allowing requests to the webhook endpoint and whether you're receiving the provided POST
data correctly.
Make sure to adjust the webhook URL to your own test endpoint from the Salla dashboard's Webhooks. And that would show you results based on that URL.
:::warning
Please verify that the activities performed in the testing endpoint do not affect your actual data.
:::
🔍 URL Endpoint Access Troubleshooting
This test will help you determine whether your webhook endpoint accepts requests from Salla. For this examination:
Create a
POST
endpoint that, whenever a request is submitted to it, adds a timestamp to a log file.Create an event (for example: order) (if your webhook was setup for order creation).
Examine the log file a few seconds after the request is done to see if it includes the written timestamp.
Check for any TLS/SSL handshake failure
Send and Inspect a
POST
request over to SallaExamine the receiving endpoint for errors
If a request log is there after the request attempt, it confirms that your server granted access to the endpoint as intended.
If it did not write to your log, there is a good probability that the request did not reach the endpoint or that your server rejected it; to resolve this, follow these steps:
Ensure that the URL in the Salla webhook settings is correct and you can check Life active webhooks.
Examine any responses from the
POST
call.
🔍 POST Data Troubleshooting
The following step is to ensure that you are receiving the POST Data appropriately.
This troubleshooting mechanism is quite similar to the one mentioned above. In this example, we'll obtain the content of the POST
request and save it to a file.
Here's an example of a successful webhook body from the order.created
event: