Developer Resources > Examples

Webhooks

 

In this section, we will explore all of the available webhooks, list some examples, and see how you can register and unregister webhooks.

Overview

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.

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 thecreated_at_min and updated_at_minfilter 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.

Available webhooks:

In the section below there are some examples of what the webhooks look like, and what the response should look like when successfully received the webhook.

 

Inventory Update

This URL is the URL that you setup on your system, so we can push updates.

Webhook Body:

{
    "account_id": "7556",
    "inventory": [
        {
            "webhook_type": "INVENTORY_UPDATE",
            "sku": "1122334459",
            "inventory": "22",
            "backorder_quantity": "0",
            "virtual": false
        }
    ]
}

Response:

{
  "code": "200",
  "Message": "Success"
}

Shipment Update

This URL is the URL that you set up on your system, so we can push updates.

Webhook Body:

{
  "test": "0",
  "fulfillment": {
    "shipment_id": 95544424,
    "partner_order_id": "MO191",
    "order_number": "MO191",
    "tracking_number": "1Z5AR6970399365193",
    "line_items": [{
      "id": "MO191-301705549",
      "shiphero_id": 407839455,
      "quantity": 1,
      "sku": "1122334581",
      "serial_numbers": [],
      "customs_description": "a description",
      "package": "Package #1",
      "lot_id": null,
      "lot_name": null,
      "lot_expiration": null
    }],
    "custom_tracking_url": "http://wwwapps.ups.com/WebTracking/track?track=yes&trackNums=1Z5AR6970399365193",
    "shipping_method": "UPS Ground",
    "shipping_carrier": "UPS",
    "shipping_address": {
      "name": "tomas wingord",
      "address1": "55 W RAILROAD AVE BLDG 4",
      "address2": "BLDG 4",
      "address_city": "GARNERVILLE",
      "address_zip": "10923-1261",
      "address_state": "NY",
      "address_country": "US"
    },
    "warehouse": "Primary",
    "warehouse_id": 11790,
    "package": {
      "length": 1,
      "width": 1,
      "height": 1,
      "weight": 336.48
    },
    "created_at": "2020-08-21 13:04:06"
  },
  "label_cost": "8.36"
}

Response:

{
  "code": "200",
  "Message": "Success"
}

Order Canceled

ShipHero will call this URL when an order is canceled.

Webhook Body:

{
  "order_number": "123456",
  "fulfillment-status": "canceled"
}

Response:

{
  "code": "200",
  "Message": "Success"
}

Capture Payment

ShipHero will call this URL to attempt to request a payment capture before the order is shipped. If success or no response is returned the order will be shipped. If a failure is returned, shipping will be stopped. This may be called multiple times – even after success, so your code should not assume that the capture has not already taken place. Your response should be a JSON response, with a message of “Success” or “Failure”.

Webhook Body:

{
  "order_number": "123456",
  "order_id": "201212475",
  "line_items": [
    {
      "id": "123",
      "quantity": 1
    }
  ]
}

Response:

{
  "code": "200",
  "Message": "Success"
}

or

{
  "code": "500",
  "Status": "Failure"
}

PO Update

This URL is the URL that you setup on your system, so we can push updates. This webhook will be called anytime a purchase order is created or updated.

Webhook Body:

{
  "test": "0",
  "purchase_order": {
    "status": "closed",
    "line_items": [
      {
        "sku": "1804760-1",
        "id": "576c42332386e",
        "quantity_received": 1
      },
      {
        "sku": "1281949-1",
        "id": "576c423323930",
        "quantity_received": 6
      },
      {
        "sku": "1178413-1",
        "id": "576c4233239ef",
        "quantity_received": 12
      },
      {
        "sku": "1845087-1",
        "id": "576c423323ab0",
        "quantity_received": 1
      },
      {
        "sku": "1001006-1",
        "id": "576c423323b6f",
        "quantity_received": 6
      },
      {
        "sku": "1688598-1",
        "id": "576c423323c2d",
        "quantity_received": 6
      },
      {
        "sku": "2011239-1",
        "id": "576c423323ceb",
        "quantity_received": 3
      },
      {
        "sku": "1844552-1",
        "id": "576c423323da9",
        "quantity_received": 12
      },
      {
        "sku": "2000411-1",
        "id": "576c423323e66",
        "quantity_received": 12
      }
    ],
    "po_id": 8603,
    "id": 1234,
    "po_number": "PO 1"
  }
}

Response:

{
  "code": "200",
  "Message": "Success"
}

Return Update

This URL is the URL that you setup on your system, so we can push updates. This webhook will be called anytime a return is created or updated.

Webhook Body:

{
  "test": "0",
  "return_id": 1329001,
  "status": "warehouse complete",
  "reason": "Too small",
  "items": [{
    "id": 2138528,
    "quantity": 1,
    "quantity_received": 0,
    "sku": "1122334465",
    "item_reason": "Small",
    "restock": 0,
    "partner_line_item_id": "MO135-301705432",
    "warehouse_id": 11200
  }],
  "order_id": 127148457,
  "partner_order_id": "MO135",
  "order_number": "MO135",
  "shop_name": "Manual Order",
  "created_at": "2020-07-15 21:43:38",
  "label_type": "Free Label",
  "label_cost": "0.00",
  "picked_up": false,
  "tracking_number": "14322345667",
  "date_used": null
}

Response:

{
  "code": "200",
  "Message": "Success"
}

Generate Label Webhook

Instead of using one of the ShipHero supported carriers, we can call a URL you provide to get the label from your endpoint. The endpoint you build must accept a JSON payload and return an image.

Contact us at support@shiphero.com or via chat with the following information:

  • Endpoint URL (Something like https://someurl.com/print-label )

  • Tracking URL (Something like https://www.trackingurl.com/?MyTrakcingNumber= )

  • Name of the method (Name they want to show when choosing the method)

Then we can register that for you and when you go to ship the order, you will choose API as the carrier and hit Print Label to generate the call.
The response must include an image in PNG or PDF format. We DO NOT support clean URLs, the URL sent to us must contain the file extension.
Ex. “http://yourwebsite.com/file.pdf” or “http://yourwebsite.com/file.png”
Any errors must be returned with a status code of 500.

Webhook Body:

{
  "shipping_name": "Manual Order Shipping Method",
  "to_address": {
    "city": "SAN FRANCISCO",
    "state": "CA",
    "zip": "94105",
    "name": "test order",
    "address_2": "",
    "country": "US",
    "address_1": "123 MAIN ST",
    "email": "none@none.com",
    "phone": "",
    "company_name": ""
  },
  "shipping_method": "My Carrier",
  "order_id": "83478763",
  "packages": [
    {
      "width": 10,
      "weight_in_oz": 11,
      "length": 10,
      "line_items": [
        {
          "tariff_code": "0",
          "price": "0.00",
          "customs_description": null,
          "customs_value": "0.00",
          "line_item_id": "225458557",
          "barcode_exists": "0",
          "partner_line_item_id": "MO114-265348960",
          "sku": "yellow-kit",
          "barcode_scanned": "0",
          "name": "Yellow Kit",
          "ignore_on_customs": false,
          "product_name": "Yellow Kit",
          "quantity": "2"
        }
      ],
      "height": 10
    }
  ],
  "order_number": "MO114",
  "partner_order_id": "MO114",
  "from_address": {
    "city": "Garnerville",
    "state": "NY",
    "zip": "10923",
    "name": "ShipHero Apparel",
    "address_2": "",
    "country": "US",
    "address_1": "123 Main St",
    "email": "hello@shiphero.com",
    "phone": "11111111111",
    "company_name": ""
  }
}

Response:

{
  "code": "200",
  "shipping_method": "Ground",
  "tracking_number": "1adddsad11",
  "cost": "5.55",
  "label": "s3.amazonaws.com/myimages/65259502/thermaltmpyjYG5K.png",
  "customs_info": "",
  "shipping_carrier": "ups"
}

or

{
  "code": "4xx or 5xx",
  "error": "Some validation error"
}

Get all your 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"
            }
          }
        ]
      }
    }
  }
}

Register a new webhook

To be able to register a new webhook you will need to use the webhook_create mutation.
If you want to update an already existing webhook you will need to delete the existing webhook and then add it again.

Webhooks available are:

  • Inventory Update
  • Shipment Update
  • Order Canceled
  • Capture Payment
  • PO Update
  • Return Update

The mutation to register a webhook could be:

mutation {
  webhook_create(data: { 
    name: "PO Update", 
    url: "https://someValidURL.com/webhook" 
  }) {
    request_id
    complexity
    webhook {
      name
      url
    }
  }
}

The field name is the webhook type you want to register to, for example, Inventory Update.

And the response for it should be something like this:

{
  "data": {
    "webhook_create": {
      "request_id": "5f04e4f10fa8bfa5ea766b56",
      "complexity": 5,
      "webhook": {
        "name": "PO Update",
        "url": "https://someValidURL.com/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" }) {
    request_id
    complexity
  }
}

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.

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