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
- Automation Rules
- 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 webhook will trigger whenever an order gets fulfilled from shipping.shiphero.com as single order or using bulkship, or when it gets fulfilled from the API.
You will notice several fields like shipping_carrier
and shipping_method
exist both inside and ourside the packages array. Those inside the packages array where added last, to better reflect the differences packages can have, and are the most accurate. The other ones are considered legacy fields and will eventually be deprecated
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" }
Automation Rules Webhook
Although not strictly a webhook, it is built similarly, and it will help you power up your API integrations just like any other of our webhooks.
By setting up an automation rule with this action, whenever the trigger conditions are met, we will send the payload in a POST call to the registered endpoint.
Use the addressable action data to identify what made the AR trigger on your endpoint, and continue with your workflow from there.
Payload:
{ "account_id": "the account id", "account_uuid": "the uuid of the account", "order_id": "the shiphero order id", "shop_name": "the orde shop_name", "order_number": "the order_number", "partner_order_id": "the partner_order_id", "action_data": "the text from the Message field in the automation rule action" }
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 is returned, the order will be shipped. If a failure (HTTP code not 200 or body code not 200) is returned, shipping will be stopped, and the order will be put in Payment Hold.
This may be called multiple times after success, for example on partially shipped order or reships, so your code should account for these cases.
Please, reach out to support to have this webhook configured in your account
Webhook Body:
{ { "webhook_type": "Capture Payment", "order_number": "#123486165", "partner_order_number": 123486165, "partner_order_id": "test no status", "account_id": 63898, "shop_name": "Amazon US", "order_id": 397707517, "line_items": [ { "id": "534534534535435345", "sku": "FU5014028", "shiphero_id": 995780973, "quantity": 1 }, { "id": "453454343543534", "sku": "FU165528", "shiphero_id": 995780972, "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. However, in a 3PL-Child Account relationship, this webhook will only work when registered in the Child Account. As the 3PL, you can register it at the Child Account level and point it to your own endpoint.
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.
This webhook requires a specific flag to be set for your account, so please contact support@shiphero.com to request that we enable the flag to trigger the Tote Complete webhooks.
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
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 Secret, which is created automatically when the account is first setup.
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