Webhooks
In this section, we will explore all of the available webhooks, list some examples, and see how you can register and unregister webhooks.
A webhook is a way for an app to provide other applications with real-time information. A webhook delivers data to other applications as it happens, meaning you get data immediately.
In ShipHero we have several different webhooks you can subscribe to, and when doing so, you should be receiving different kind of information, for example, if you subscribe to the Inventory Update webhook, we will be sending the webhook each time your inventory gets updated.
When we send the webhook we wait for a response:
HEADERS: Content-Type:application/json
BODY:
{
  "code": "200",
  "Status": "Success"
}The timeout for this response to get back is 10 seconds with 5 retries per trigger. For Generate Label Webhook the timeout is 20 seconds.
Note
Although it is not often, it is possible for a webhook not to fire, and that is why your app should not rely just on receiving data from our webhooks.
The webhook delivery is not always guaranteed, so we strongly suggest implementing reconciliation jobs to periodically fetch data from ShipHero.
Our most important Queries have both the created_at_min and updated_at_min filter parameters, which will allow you to build a job that fetches all resources that have been created or updated since the last time the job ran.
To be able to register a new webhook you will need to use the webhook_create mutation.
If you want to update an existing webhook, you will need to delete the existing one and then add it again.
Webhooks available are:
- Inventory Update
 - Inventory Change
 - Shipment Update
 - Automation Rules
 - Order Canceled
 - Capture Payment
 - PO Update
 - Return Update
 - Tote Complete
 - Tote Cleared
 - Order Packed Out
 - Package Added
 - Print Barcode
 - Order Allocated
 - Order Deallocated
 - Shipment ASN
 - Generate Label Webhook
 
Register a Webhook
The mutation to register a webhook could be:
mutation {
  webhook_create(
    data: {
      name: "Inventory Update"
      url: "https:someValidURL.net/"
      shop_name: "api"
    }
  ) {
    request_id
    complexity
    webhook {
      shared_signature_secret
    }
  }
}The field name is the webhook type you want to register to, for example, Inventory Update. Use the name as written in the list above, respecting spaces and capitals.
The field shop_name is an identifier that doesn’t necessarily need to be the shop’s name. If you have more than one endpoint you need the same webhook sent to, using a different Shop Name will allow you to register a second webhook of the same type.
The response for it should be something like this:
{
  "data": {
    "webhook_create": {
      "request_id": "60dd12525e4d76b3ee093d7d",
      "complexity": 5,
      "webhook": {
        "shared_signature_secret": "b0b588622fb191c3d96c34c5f929fbae04b94e74"
      }
    }
  }
}The shared_signature_secret that you will get in return is the one you will be used to validate the webhook using the HTTP_X_SHIPHERO_HMAC_SHA256
shared_signature_secret will only display once, when first registering the webhook.
If you are using a 3PL account, webhooks need to be registered on the Customer account and not the 3PL account to trigger correctly.
Un-register an existing webhook
To be able to un-register an existing webhook you will need to use the webhook_delete mutation, for example:
mutation {
  webhook_delete(data: { 
    name: "PO Update", 
    shop_name: "api" }) 
  {
    request_id
    complexity
  }
}List all registered webhooks
If you need to get a list of all the webhooks you have registered to your account, you will have to use the webhooks query:
query {
  webhooks {
    request_id
    complexity
    data {
      edges {
        node {
          id
          legacy_id
          account_id
          shop_name
          name
          url
          source
        }
      }
    }
  }
}And the response for it should be something like this:
{
  "data": {
    "webhooks": {
      "request_id": "5f04e1fcda845a0a76d4b102",
      "complexity": 101,
      "data": {
        "edges": [
          {
            "node": {
              "id": "QXBpV2ViaG9vazoxNjE0ODc4",
              "legacy_id": 1614878,
              "account_id": "QWNjb3VudDo2MzM0",
              "shop_name": null,
              "name": "Order Canceled",
              "url": "https://someURL.x.webhook.net",
              "source": "api"
            }
          },
          {
            "node": {
              "id": "QXBpV2ViaG9vazoxNjE0Nzky",
              "legacy_id": 1614792,
              "account_id": "QWNjb3VudDo2MzM0",
              "shop_name": null,
              "name": "PO Update",
              "url": "https://someURL.x.webhook.net",
              "source": "api"
            }
          },
          {
            "node": {
              "id": "QXBpV2ViaG9vazoxNjE1MDQy",
              "legacy_id": 1615042,
              "account_id": "QWNjb3VudDo2MzM0",
              "shop_name": null,
              "name": "Return Update",
              "url": "https://someURL.x.webhook.net",
              "source": "api"
            }
          }
        ]
      }
    }
  }
}Request Verification
Webhooks data sent from ShipHero will need to be verified with the secret found within the API section of the Settings area.
Each Webhook request includes a x-shiphero-hmac-sha256 header which is generated using the app’s shared secret, along with the data sent in the request.
Generate Label Webhook uses exclusively the “default” API Secret, unless the order’s shop name matches a shop name in the API Secrets list, in which case it will use that secret.
You can retrieve all your API secrets from this link. If the default secret is missing or has been replaced, you can generate a new one and name it accordingly.
To verify that the request came from ShipHero, compute the HMAC digest according to the following algorithm and compare it to the value in the x-shiphero-hmac-sha256 header.
If they match, you can be sure that the Webhook was sent from ShipHero and the data has not been compromised.
Note that if you are using a Rack-based framework such as Ruby on Rails or Sinatra the header you are looking for is HTTP_X_SHIPHERO_HMAC_SHA256
Below is a simple example in Python, showing how one might verify a webhook request.
def verify_webhook_hmac(secret, data, hmac_signature): 
''' Compares the incoming signed request with our generated signature to verify 
source :param secret: shared secret :param data: json string of post params :param hmac_signature: String 
received from HMAC header :return: Boolean ''' 
import hmac import hashlib import base64
digest = hmac.new(secret, msg=data, digestmod=hashlib.sha256).digest()
    calculated_signature = base64.b64encode(digest).decode()
    verified = True
    if calculated_signature != hmac_signature:
        verified = False
    return verified