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_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.
Available webhooks:
- Inventory Update
- Shipment Update
- Order Canceled
- Capture Payment
- PO Update
- Return Update
- Tote Complete
- Tote Cleared
- Order Packed Out
- Package Added
- Order Allocated
- Order Deallocated
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. This webhook will be called anytime the On Hand quantity changes. The warehouse returned in the webhook body will always be the warehouse that the movement occurred in.
Webhook Body:
{ "account_id": 7556, "account_uuid": "QWNjb3VudDo3NTU2", "webhook_type": "Inventory Update", "inventory": [ { "sku": "100100", "inventory": "37", "backorder_quantity": "1", "on_hand": "45", "virtual": false, "updated_warehouse": { "warehouse_id": 13841, "warehouse_uuid": "V2FyZWhvdXNlOjEzODQx", "identifier": "CA", "inventory": "35", "backorder_quantity": "0", "on_hand": "35" } } ] }
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", "webhook_type": "Shipment Update", "fulfillment": { "shipment_id": 315518042, "shipment_uuid": "U2hpcG1lbnQ6MzE1NTE4MDQy", "warehouse": "Primary", "warehouse_id": 76733, "warehouse_uuid": "V2FyZWhvdXNlOjc2NzMz", "webhook_type": "Shipment Update", "partner_order_id": "test-track-url", "order_number": "test-track-url", "tracking_number": "15619819718", "line_items": [ { "id": "test-track-url-363346570", "shiphero_id": 828656700, "quantity": 1, "sku": "FU2314R", "serial_numbers": [], "customs_description": "", "package": "Package #1", "lot_id": null, "lot_name": null, "lot_expiration": null }, { "id": "test-track-url-363343850", "shiphero_id": 828656701, "quantity": 1, "sku": "FU3314R", "serial_numbers": [], "customs_description": null, "package": "Package #2", "lot_id": null, "lot_name": null, "lot_expiration": null } ], "custom_tracking_url": "", "package_number": 1, "total_packages": 2, "shipping_method": "Super Shipping", "shipping_carrier": "API - TomasFD", "shipping_address": { "name": "Tomas Two", "address1": "1308 DREXEL AVE", "address2": "APT 208", "address_city": "MIAMI BEACH", "address_zip": "33139-8126", "address_state": "FL", "address_country": "US" }, "package": { "length": 0.39, "width": 0.39, "height": 0.39, "weight": 13.12 }, "completed": true, "created_at": "2022-12-26 15:29:26", "order_uuid": "T3JkZXI6MzI0ODcxNzI5", "order_gift_note": "" }, "total_packages": 2, "packages": [ { "name": "Package #1", "weight_in_oz": 13.12, "width": 0.39, "length": 0.39, "height": 0.39, "line_items": [ { "line_item_id": 828656700, "partner_line_item_id": "test-track-url-363346570", "sku": "FU2314R", "product_name": "FUJIFILM XF 23mm f/1.4 R LM WR Lens", "customs_description": "", "tariff_code": "0", "price": 899, "quantity": 1, "weight": 13.12, "customs_value": 0, "ignore_on_customs": false, "country_of_manufacture": "", "lot_id": null, "lot_name": null, "lot_expiration": "" } ], "shipping_label": { "shipping_carrier": "API - TomasFD", "shipping_method": "Super Shipping", "shipping_name": "Manual Order Shipping Method", "cost": 100, "tracking_number": "15619819718", "tracking_url": "https://trackingurl.com/15619819718" }, "shipping_address": { "name": "Tomas Two", "address1": "1308 DREXEL AVE", "address2": "APT 208", "address_city": "MIAMI BEACH", "address_zip": "33139-8126", "address_state": "FL", "address_country": "US" }, "box_code": "02", "box_id": 16651, "box_name": "12x7x7" }, { "name": "Package #2", "weight_in_oz": 12.7, "width": 0.39, "length": 0.39, "height": 0.39, "line_items": [ { "line_item_id": 828656701, "partner_line_item_id": "test-track-url-363343850", "sku": "FU3314R", "product_name": "FUJIFILM XF 33mm f/1.4 R LM WR Lens ", "customs_description": null, "tariff_code": "0", "price": 799, "quantity": 1, "weight": 12.7, "customs_value": 0, "ignore_on_customs": false, "country_of_manufacture": "", "lot_id": null, "lot_name": null, "lot_expiration": "" } ], "shipping_label": { "shipping_carrier": "API - TomasFD", "shipping_method": "Mega Shipping", "shipping_name": "Manual Order Shipping Method", "cost": 100, "tracking_number": "63721453534", "tracking_url": "https://trackingurl.com/63721453534" }, "shipping_address": { "name": "Tomas Two", "address1": "1308 DREXEL AVE", "address2": "APT 208", "address_city": "MIAMI BEACH", "address_zip": "33139-8126", "address_state": "FL", "address_country": "US" }, "box_code": "02", "box_id": 16651, "box_name": "12x7x7" } ] }
Response:
{ "code": "200", "Message": "Success" }
Order Canceled
ShipHero will call this URL when an order is canceled.
Webhook Body:
{ "order_number": "9035013-2", "partner_order_id": "9035013-2", "fulfillment-status": "canceled", "order_id": 389118717, "order_uuid": "T3JkZXI6Mzg5MTE4NzE3", "shop_name": "public-api", "shop_order_number": "9035013-2", "webhook_type": "Order 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”.
Please, reach out to support to have this webhook configured in your account
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": { "id": 1070110, "po_number": "PO 31", "po_id": 31, "po_uuid": "UHVyY2hhc2VPcmRlcjoxMDcwMTEw", "line_items": [ { "id": "628e770348136", "quantity": 10, "quantity_received": 5, "sku": "FUXT4B", "vendor_id": 423049, "vendor_uuid": "VmVuZG9yOjQyMzA0OQ==", "vendor_account_number": null, "vendor_sku": "" }, { "id": "628e770348139", "quantity": 10, "quantity_received": 5, "sku": "FU165528", "vendor_id": 423049, "vendor_uuid": "VmVuZG9yOjQyMzA0OQ==", "vendor_account_number": null, "vendor_sku": "" }, { "id": "628e77034813b", "quantity": 10, "quantity_received": 5, "sku": "FU5014028", "vendor_id": 423049, "vendor_uuid": "VmVuZG9yOjQyMzA0OQ==", "vendor_account_number": null, "vendor_sku": "" }, { "id": "628e77034813d", "quantity": 10, "quantity_received": 5, "sku": "FU81628WRB", "vendor_id": 423049, "vendor_uuid": "VmVuZG9yOjQyMzA0OQ==", "vendor_account_number": null, "vendor_sku": "" }, { "id": "628e77034813e", "quantity": 10, "quantity_received": 5, "sku": "FU10040045", "vendor_id": 423049, "vendor_uuid": "VmVuZG9yOjQyMzA0OQ==", "vendor_account_number": null, "vendor_sku": "" } ], "warehouse_id": 76733, "status": "pending", "webhook_type": "PO Update" } }
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", "webhook_type": "Return Update", "return_id": 3394303, "return_uuid": "UmV0dXJuOjMzOTQzMDM=", "status": "pending", "reason": "", "items": [ { "id": 5378501, "uuid": "UmV0dXJuSXRlbTo1Mzc4NTAx", "quantity": 50, "quantity_received": 0, "sku": "CUTENESS", "item_reason": "Found it cheaper", "restock": 0, "partner_line_item_id": "Order #243-355933727", "warehouse_id": 3141 } ], "order_id": 272271706, "order_uuid": "T3JkZXI6MjcyMjcxNzA2", "partner_order_id": "Order #243", "order_number": "Order #243", "shop_name": "Manual Order", "created_at": "2022-05-24 18:34:33", "label_type": "Self Return", "label_cost": "0.00", "picked_up": false, "tracking_number": "420856539274890326147006581374", "date_used": null }
Response:
{ "code": "200", "Message": "Success" }
Tote Complete
This URL is the URL that you setup on your system, so we can push updates. This webhook will be called anytime a Tote Pick is completed using the Multi Item Batch Picking or Single Item Batch Picking.
Webhook Body:
{ "webhook_type": "Tote Complete", "totes": [ { "tote_name": "Tote-14156034", "tote_uuid": "VG90ZToxNDE1NjAzNA==", "tote_barcode": "341504915", "orders": [ { "order_number": "TWO", "gift_note": "", "items": [ { "quantity": 1, "sku": "1234567", "weight": "0.0500 oz", "height": "1.00 in", "width": "1.00 in", "length": "1.00 in" }, { "quantity": 1, "sku": "45678", "weight": "0.0500 oz", "height": "1.00 in", "width": "1.00 in", "length": "1.00 in" }, { "quantity": 1, "sku": "456378", "weight": "0.0500 oz", "height": "1.00 in", "width": "1.00 in", "length": "1.00 in" }, { "quantity": 1, "sku": "98765", "weight": "0.0500 oz", "height": "1.00 in", "width": "1.00 in", "length": "1.00 in" } ] } ] } ], "batch_id": "ddc68fc87baa4b9bab9f533d8e4d4531b58c4c6d0a9f755313269f4e2f396902" }
Response:
{ "code": "200", "Message": "Success" }
Tote Cleared
This URL is the URL that you setup on your system, so we can push updates. This webhook will be called anytime a Tote is cleared from the Tote page or from within an order.
Webhook Body:
{ "tote_id": "503901030", "tote_name": "Green-L", "reason": "manual", "items": [ { "order_id": 240144078, "line_item_id": 633965574, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240156684, "line_item_id": 633994555, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240151715, "line_item_id": 633983940, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240150619, "line_item_id": 633981282, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240144183, "line_item_id": 633965820, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240146458, "line_item_id": 633971225, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240144989, "line_item_id": 633967729, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240144928, "line_item_id": 633967563, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240167510, "line_item_id": 634020166, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 240146046, "line_item_id": 633970191, "pick_id": 0, "sku": "FU10040045" }, { "order_id": 224832016, "line_item_id": 598296059, "pick_id": 0, "sku": "FUXT4B" }, { "order_id": 223369380, "line_item_id": 595859678, "pick_id": 0, "sku": "UX100VS" }, { "order_id": 219252244, "line_item_id": 585045021, "pick_id": 0, "sku": "0" } ] }
Response:
{ "code": "200", "Message": "Success" }
Order Packed Out
This URL is the URL that you setup on your system, so we can push updates. This webhook will be called anytime an order is packed out from a Tote.
Webhook Body:
{ "webhook_type": "Order Packed Out", "tote_id": "14156034", "tote_uuid": "VG90ZToxNDE1NjAzNA==", "tote_name": "Tote-14156034", "order_id": 203849703, "order_uuid": "T3JkZXI6MjAzODQ5NzAz", "items": [ { "order_id": 203849703, "order_uuid": "T3JkZXI6MjAzODQ5NzAz", "line_item_id": 549638170, "pick_id": 123425, "sku": "1122335454" } ] }
Response:
{ "code": "200", "Message": "Success" }
Package Added
This URL is the URL that you setup on your system, so we can push updates. This webhook will be called anytime a Package is added to a Shipping Container.
Webhook Body:
{ "test": "0", "fulfillment": { "webhook_type": "Package Added", "shipment_id": 168700093, "shipment_uuid": "U2hpcG1lbnQ6MTY4NzAwMDkz", "partner_order_id": "MO348", "order_number": "MO348", "warehouse": "Primary", "warehouse_id": 11790, "warehouse_uuid": "V2FyZWhvdXNlOjExNzkw", "shipping_label_id": 119614476, "shipping_label_uuid": "U2hpcHBpbmdMYWJlbDoxMTk2MTQ0NzY=", "package_added_at": "2021-07-24T01:50:56" } }
Response:
{ "code": "200", "Message": "Success" }
Order Allocated
This URL is the URL that you setup on your system, so we can push updates. This webhook will be called anytime an Order gets allocated.
Webhook Body:
{
"webhook_type": "Order Allocated",
"allocation_reference": 362137624,
"account_id": 6334,
"account_uuid": "QWNjb3VudDo2MzM0",
"warehouse_id": 11790,
"warehouse_uuid": "V2FyZWhvdXNlOjExNzkw",
"allocated_at": "2021-07-24T02:03:01",
"order_number": "MO351",
"order_id": 204159062,
"order_uuid": "T3JkZXI6MjA0MTU5MDYy",
"partner_order_id": "MO351",
"line_items": [
{
"id": 550365415,
"item_uuid": "TGluZUl0ZW06NTUwMzY1NDE1",
"partner_line_item_id": "MO351-301706334",
"quantity": 1,
"sku": "1122335364",
"is_kit_component": false,
"created_at": "2021-07-24T02:03:01"
}
]
"ready_to_ship": 1
}
Response:
{ "code": "200", "Message": "Success" }
Order Deallocated
This URL is the URL that you setup on your system, so we can push updates. This webhook will be called anytime an Order gets deallocated.
Webhook Body:
{ "webhook_type": "Order Deallocated", "allocation_reference": 362137624, "account_id": 6334, "account_uuid": "QWNjb3VudDo2MzM0", "order_id": 204159062, "order_number": "MO351", "order_uuid": "T3JkZXI6MjA0MTU5MDYy", "partner_order_id": "MO351", "deallocated_at": "2021-07-24T02:07:56" }
Response:
{ "code": "200", "Message": "Success" }
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 existing webhook, you will need to delete the existing one and then add it again.
Webhooks available are:
-
- Inventory Update
- Shipment Update
- Order Canceled
- PO Update
- Return Update
- Tote Complete
- Tote Cleared
- Order Packed Out
- Package Added
- Order Allocated
- Order Deallocated
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 } }
Generate Label Webhook
If you would like to have us register one for you, please email support@shiphero.com.
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/PDF.
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 the name you provided as the method, and hit Print Label to trigger 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 or 400.
Webhook Body:
{ "shipping_method": "API Shipping", "order_id": 242662901, "profile": "default", "fulfillment_status": "pending", "order_number": "MO31", "shop_name": "Manual Order", "account_id": 5927, "partner_order_id": "MO31", "shipping_name": "Manual Order Shipping Method", "tax_type": null, "tax_id": null, "incoterms": null, "currency": "USD", "from_address": { "name": "ShipHero", "company_name": "ShipHero", "address_1": "123 First St.", "address_2": "", "email": "help@shiphero.com", "city": "Anytown", "state": "CA", "zip": "90210", "country": "US", "phone": "1234567890" }, "to_address": { "name": "Test Order", "company_name": "", "address_1": "1 MAIN ST", "address_2": "", "email": "help@shiphero.com", "city": "Anytown", "state": "CA", "zip": "90210", "country": "US", "phone": "1234567890" }, "packages": [ { "name": "Package 1", "weight_in_oz": 4, "width": 12, "length": 15, "height": 4, "line_items": [ { "sku": "shiphero-socks-black", "tariff_code": "00.00.00.000", "price": 0, "customs_description": "ShipHero Socks - Black", "customs_value": "0.01", "line_item_id": 639727287, "quantity": 1, "weight": 1.92, "partner_line_item_id": "MO31-299273207", "id": "MO31-299273207", "country_of_manufacture": "", "product_name": "ShipHero Socks - Black", "name": "ShipHero Socks - Black", "ignore_on_customs": false }, { "sku": "shiphero-socks-blue", "tariff_code": "00.00.00.000", "price": 0, "customs_description": "ShipHero Socks - Blue", "customs_value": "0.01", "line_item_id": 639727288, "quantity": 1, "weight": 1.92, "partner_line_item_id": "MO31-299273245", "id": "MO31-299273245", "country_of_manufacture": "", "product_name": "ShipHero Socks - Blue", "name": "ShipHero Socks - Blue", "ignore_on_customs": false } ], "box_code": "custom", "box_id": 5612, "box_name": "12x15 Poly Mailer" }, { "name": "Package 2", "weight_in_oz": 1.08, "width": 8, "length": 12, "height": 2, "line_items": [ { "sku": "shiphero-hero", "tariff_code": "00.00.00.000", "price": 0, "customs_description": "ShipHero Hero ", "customs_value": "0.01", "line_item_id": 639727284, "quantity": 1, "weight": 0.92, "partner_line_item_id": "MO31-299273995", "id": "MO31-299273995", "country_of_manufacture": "", "product_name": "ShipHero Hero ", "name": "ShipHero Hero ", "ignore_on_customs": false }, { "sku": "shiphero-knit-hat", "tariff_code": "00.00.00.000", "price": 0, "customs_description": "ShipHero Knit Hat ", "customs_value": "0.01", "line_item_id": 639727285, "quantity": 1, "weight": 2.19, "partner_line_item_id": "MO31-299273169", "id": "MO31-299273169", "country_of_manufacture": "", "product_name": "ShipHero Knit Hat ", "name": "ShipHero Knit Hat ", "ignore_on_customs": false } ], "box_code": "custom", "box_id": 5565, "box_name": "2 x 8 Poly Mailer" } ] }
Single Package Response
{ "code": "200", "shipping_method": "Ground", "tracking_number": "456123789", "cost": "5.55", "label": "https://url-to-label.com", "customs_info": "", "shipping_carrier": "ups", "tracking_url": "https://mycarrier.com/456123789" }
Multi Package Response
Note: You can use this format response for single packages as well.
{ "code": "200", "packages":[ { "name": "Package 2", "shipping_method": "Ground", "tracking_number": "987654321", "cost": "20.20", "label": "https://url-to-label.com/package2.pdf", "customs_info": "", "shipping_carrier": "ups", "tracking_url": "https://mycarrier.com/987654321" }, { "name": "Package 1", "shipping_method": "Ground", "tracking_number": "123456789", "cost": "10.10", "label": "https://url-to-label.com/package1.pdf", "customs_info": "https://url-to-label.com/customs1.pdf", "shipping_carrier": "ups", "tracking_url": "https://mycarrier.com/123456789" } ] }
or
{ "code": "4xx or 5xx", "error": "Some validation error" }
Response fields params:
- shipping_carrier:
- Non-mandatory. We will use API for all API methods.
- varchar(45)
- shipping_method:
- Non-mandatory. We will use the same name sent when creating the method.
- varchar(45)
- cost:
- Non-mandatory. We will use 0.00 if the field is not sent.
- Float(6,2). Must be sent as a string.
- tracking_number:
- Non-mandatory. Se note below.
- varchar(45). We will truncate any extra characters rendering the tracking link unusable.
- label:
- Mandatory.
- varchar(255)
- We DO NOT support clean URLs, must contain the file extension.
- customs_info:
- Non-mandatory. We will leave it blank if not sent
- varchar(255)
- We DO NOT support clean URLs, must contain the file extension.
- tracking_url:
- Non-mandatory. See note below
- varchar(255)
NOTE on Tracking URLs:
- The tracking URL we use for the label is the sum of the
tracking_number
sent in the Generate Label Webhook response and the Tracking URL sent when creating the method. - If no
tracking_number
is sent, we will leave it blank and no tracking link will be provided. - If the
tracking_url
field is present in the response, this value will override what has been explained above. - If you are sending the
tracking_url
field, make sure to send thetracking_number
field. We will use what’s on this field to set the display text for the tracking_url in the UI.
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 Key, which is created automatically when the account is first setup
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