# Using webhooks

### About webhooks <a href="#about-webhooks" id="about-webhooks"></a>

Webhooks are a useful tool for apps that want to execute code after a specific event occurs on a shop, for example, after a customer creates a cart on the storefront, or a merchant creates a new product in the ShopBase admin.

Instead of having your app periodically poll a shop for a specific event, you can register a webhook for the event and create an HTTP endpoint as your webhook receiver. Whenever the event occurs, a webhook is sent to the endpoint. This approach uses less API requests, making it easier to stay within API call limits while building more robust apps. Webhook event data can be stored as JSON or XML.

Common webhook use cases include the following:

* Sending notifications to IM clients and pagers
* Collecting data for data-warehousing
* Integrating with accounting software
* Filtering order items and informing shipping companies about orders
* Removing customer data from a database for app uninstalls

### Configuring webhooks <a href="#configuring-webhooks" id="configuring-webhooks"></a>

You can configure a webhook using the API or in the ShopBase admin (later).

#### Configure a webhook using the API <a href="#configure-a-webhook-using-the-api" id="configure-a-webhook-using-the-api"></a>

You can configure a webhook by making a HTTP POST request to the [Webhook resource](https://api-doc.shopbase.com/#tag/sbase-webhook-api) in the REST Admin API.

After you've created a webhook, you're presented with a secret to validate its integrity. You can also [test](https://help.shopify.com/en/api/getting-started/webhooks#testing-webhooks-configured-using-the-shopify-admin) it.

### Testing webhooks

When testing webhooks, you can run a local server or use a publicly available service such as [Beeceptor](https://beeceptor.com/). If you decide to run a server locally, then you need to make it publicly available using a service such as [**Pagekite**](https://pagekite.net/) or [**ngrok**](https://ngrok.com/). The following URLS do not work as endpoints for webhooks:

* Localhost
* Any URL ending in the word "internal". For example, `thisshop.com/internal`
* Domains like `www.example.com`
* ShopBase domains such as `shopbase.com` and `onshopbase.com`

### Creating an endpoint for webhooks <a href="#creating-an-endpoint-for-webhooks" id="creating-an-endpoint-for-webhooks"></a>

Your endpoint must be an HTTPS webhook address with a valid SSL certificate that can correctly process event notifications as described below. You can also implement verification to make sure webhook requests originate from ShopBase.

#### Payloads <a href="#payloads" id="payloads"></a>

Payloads contain a JSON or XML object with the data for the webhook event. The contents and structure of each payload varies depending on the [subscribed event](https://developers.shopbase.com/build-an-app/making-your-first-request/using-webhooks/webhook-events-and-topics).

#### Receiving a webhook <a href="#receiving-a-webhook" id="receiving-a-webhook"></a>

After you register a webhook URL, ShopBase issues a HTTP POST request to the URL specified every time that event occurs. The request's POST parameters contain XML/JSON data relevant to the event that triggered the request.

ShopBase verifies SSL certificates when delivering payloads to HTTPS webhook addresses. Make sure your server is correctly configured to support HTTPS with a valid SSL certificate.

#### Responding to a webhook <a href="#responding-to-a-webhook" id="responding-to-a-webhook"></a>

Your webhook acknowledges that it received data by sending a 200 OK response. Any response outside of the 200 range, including 3XX HTTP redirection codes, indicates that you did not receive the webhook. ShopBase does not follow redirects for webhook notifications and considers them to be an error response.

**Frequency**

ShopBase has implemented a five second timeout period and a retry period for subscriptions. ShopBase waits five seconds for a response to each request to a webhook. If there is no response, or an error is returned, then ShopBase retries the connection 19 times over the next 48 hours. A webhook is deleted if there are 19 consecutive failures.

{% hint style="info" %}
If the webhook subscription was created through the API, then notifications about pending deletions are sent to the support email associated with the app. If the webhook was created using ShopBase admin, then notifications are sent to the store owner's email address.
{% endhint %}

To avoid timeouts and errors, consider deferring app processing until after the webhook response has been successfully sent.

### Verifying webhooks

Webhooks created through the API by a ShopBase App are verified by calculating a digital signature. Each webhook request includes a [base64-encoded](https://tools.ietf.org/html/rfc4648#section-4) **X-ShopBase-Hmac-SHA256** header, which is generated using the app's shared secret along with the data sent in the request.

Webhooks created through the ShopBase admin are verified using the secret displayed in the **Webhooks** section of the **Notifications** page.

To verify that the request came from ShopBase, compute the HMAC digest according to the following algorithm and compare it to the value in the **X-ShopBase-Hmac-SHA256** header. If they match, then you can be sure that the webhook was sent from ShopBase.

{% hint style="info" %}
If you're using a Rack based framework such as Ruby on Rails or Sinatra, then the header you are looking for is HTTP\_X\_SHOPBASE\_HMAC\_SHA256.
{% endhint %}

You can follow [SampleApp code to verify webhook hmac](https://bitbucket.org/brodev/sbase-sampleapp/src/101857456d2898e2ff249daee30ef893f96ac8a5/backend/controllers/orders.js#lines-85:96) or below example uses PHP to verify a webhook request:

```php
<?php

define('SHOPBASE_APP_SECRET', 'my_shared_secret');

function verify_webhook($data, $hmac_header) {
  $calculated_hmac = base64_encode(hash_hmac('sha256', $data, SHOPBASE_APP_SECRET, true));
  return hash_equals($hmac_header, $calculated_hmac);
}


$hmac_header = $_SERVER['HTTP_X_SHOPBASE_HMAC_SHA256'];
$data = file_get_contents('php://input');
$verified = verify_webhook($data, $hmac_header);
error_log('Webhook verified: '.var_export($verified, true)); //check error.log to see the result
```

### Best practices <a href="#best-practices" id="best-practices"></a>

In the event that your app goes offline for an extended period of time, you can recover your webhooks by re-registering your webhooks and importing the missing data.

#### Re-registering webhooks <a href="#re-registering-webhooks" id="re-registering-webhooks"></a>

To re-register the webhooks, consult the app's code that initially registered the webhooks. You can add a check that fetches all the existing webhooks and only registers the ones that you need.

#### Importing missing data <a href="#importing-missing-data" id="importing-missing-data"></a>

To import the missing data, you can fetch data from the outage period and feed it into your webhook processing code.

{% hint style="info" %}
Your app should not rely solely on receiving data from ShopBase webhooks. Since webhook delivery is not always guaranteed, you should implement reconciliation jobs to periodically fetch data from ShopBase. Most query endpoints support both the `created_at_min` and `updated_at_min` filter parameters. These filters can be used to build a job that fetches all resources that have been created or updated since the last time the job ran.
{% endhint %}
