Webhooks
When an event occurs, the platform will send a POST request to subscribed clients. Clients can subscribe to specific events using the webhook system.
There are two types of webhooks:
- those created in the admin system (or using the API with legacy credentials)
- those created by OAuth clients using the API
Each webhook has a topic and a URL. The URL must be valid and use HTTPS. A verification request will be sent immediately after the webhook is created (this request can be resent using the API or the admin system).
The API endpoint for managing webhooks (/webhooks) requires the use_webhooks permission when using OAuth authentication. The webhooks created using legacy credentials (basic authentication) will be identical to the ones created using the admin system.
Webhook handlers must respond within 5 seconds and with a status code of 200 OK (anything else will be considered a failure). Failed requests will be retried hourly for up to 24 hours. After 24 failed attempts the webhook will be automatically disabled.
Webhooks created using the admin system will be signed with the secret displayed on the webhooks page. Webhooks created using the API will be signed with the client's signature secret. Webhooks created using the API with legacy credentials will be signed with the admin secret, if any. The signature is sent in the X-ShopWired-Signature HTTP header.
The webhook request payload is a JSON object with two properties: timestamp (the time when the request was sent) and event. Each event has the following properties:
- id
- businessId
- createdAt
- topic
- subjectId
- data
The verification request payload is a JSON object with two properties:
- timestamp
- verificationToken
The following subject types are avilable:
Subject | Description |
---|---|
product | Products are individual items that are avilable in your shop. |
category | Categories allow you to organise your products into groups of similar items. |
brand |
Brands are similar to categories, allowing you to categorise your products with brands. Brands are accessible by installing the Brands app. |
tag |
Tags are another method of grouping products, similar to categories and brands. These are a legacy feature, replaced by categories and brands. |
customer | A customer is any person that places an order on your online store, or creates an account on your website using the 'create account' form. |
order | When a customer successfully completes the check out process on your website, an order will be generated. |
The following topics are available:
Topic | Trigger |
---|---|
product.created | When a product is created using either the ShopWired admin panel or the ShopWired API. |
product.updated | When a product is updated using either the ShopWired admin panel or the ShopWired API. |
product.deleted | When a product is deleted using either the ShopWired admin panel or the ShopWired API. |
product.stock_changed | When a product's stock is updated using either the ShopWired admin panel or the ShopWired API. |
category.created | When a category is created using either the ShopWired admin panel or the ShopWired API. |
category.updated | When a category is updated using either the ShopWired admin panel or the ShopWired API. |
category.deleted | When a category is deleted using either the ShopWired admin panel or the ShopWired API. |
brand.created | When a brand is created using either the ShopWired admin panel or the ShopWired API. |
brand.updated | When a brand is updated using either the ShopWired admin panel or the ShopWired API. |
brand.deleted | When a brand is deleted using either the ShopWired admin panel or the ShopWired API. |
tag.created | When a tag is created using either the ShopWired admin panel or the ShopWired API. |
tag.updated | When a tag is updated using either the ShopWired admin panel or the ShopWired API. |
tag.deleted | When a tag is deleted using either the ShopWired admin panel or the ShopWired API. |
customer.created |
When a customer is created using either the ShopWired admin panel or the ShopWired API. Can also be triggered during the checkout process. |
customer.updated |
When a customer's details are updated using either the ShopWired admin panel or the ShopWired API. Can also be triggered if a customer updates their details. |
customer.deleted |
When a customer is deleted using either the ShopWired admin panel or the ShopWired API. |
order.created | This topic is currently unused. |
order.updated | When an order is updated using either the ShopWired admin panel or the ShopWired API. |
order.deleted | When an order is deleted using either the ShopWired admin panel or the ShopWired API. |
order.finalized | When an order is completed / paid. |
order.status_changed | When an order's status is changed from the order list page within the admin page or through the ShopWired API. |
batch.completed | When a batch operation (E.g. imports) is completed. |
The signature is a HMAC (SHA-256) digest of the request payload.
Below is a sample webhook request:
{ "timestamp": "Tue, 23 Oct 2018 12:08:23 +0000", "event": { "id": 123456, "businessId": 123456, "createdAt": "Tue, 23 Oct 2018 12:08:23 +0000", "topic": "product.updated", "subjectType": "product", "subjectId": 123456, "data": { "object": { ... } } } }
The data property will contain relevant event information. Usually it will be a JSON object with a single property named object (the API representation of the relevant resource).
For the product.stock_changed topic data will be a JSON object with three properties:
- sku
- isVariation
- newQuantity
For the order.status_changed topic data will be a JSON object with a single property named newStatus (the API representation of the new order status).
For the batch.completed topic data will be a JSON object with two properties:
- action
- count
count is the number of affected items.
The type of affected items is represented by subjectType.
An /events API endpoint is also available for retrieving recent events. The topic, since_id, created_before and created_after query parameters can be used to filter events.
Code Samples
Code Samples
Code samples for verification of webhooks using PHP are provided below. These are for guidance purposes only.
PHP Sample Code - Initial Verification Of Webhook
This code is used for responding to the initial request sent by the ShopWired platform
when a webhook is initially setup.
This example is written in PHP using the Slim framework.
// Using: Slim\Http\Request // Using: Slim\Http\Response public function webhook_update(Request $request, Response $response) { // verify request - NOTE: This function is used to check the request came from the ShopWired platform. // NOTE: the verifyWebhookRequest function is shown lower down on this page. if(!$this->verifyWebhookRequest($request)) { // Log that the webhook signature could not be verified. Request may not have originated from the ShopWired platoform! return $response->withStatus(404); } // handle verification request $parsed_body = $request->getParsedBody();if(is_array($parsed_body) && !empty($parsed_body['verificationToken'])) { // NOTE: This code will only run during the verification request. The verificationToken is not included in normal webhook requests. $signed_verification_token = hash_hmac('sha256', $parsed_body['verificationToken'], INSERT_WEBHOOK_SECRET_HERE); return $response->write($signed_verification_token)->withStatus(200); }// Continue with code that should run if the request is a normal webhook request // ... //... //... // NOTE: your function should always respond within 5 seconds and it should respond with a status of 200 OK return $response->withStatus(200); }
PHP Sample Code - Verify The Webhook Came From The ShopWired Platform
This code is used for checking every webhook request, to ensure the request originated
from the ShopWired platform
This example is written in PHP using the Slim framework.
// Using: Slim\Http\Request protected function verifyWebhookRequest(Request $request): bool { // validate input $body = $request->getBody()->getContents(); $signature = $request->getHeaderLine('X-ShopWired-Signature'); if(!$body || !$signature) { // Invalid webhook request return false; } // verify signature $expected_signature = hash_hmac('sha256', $body, INSERT_WEBHOOKS_SECRET_HERE); if($signature !== $expected_signature) { // Invalid webhook signature // Log received and expected signature return false; } return true; }