Webhooks Guide
Introduction |
POST bodies |
Webhook versions |
Guarantees and caveats |
Requirements |
Secrets |
Verification |
Signature verification code samples |
API reference |
Introduction
The Webhooks API allows your application to stay informed about events of interest on the Shipwire platform, in near real-time. By creating a Webhook, your application can subscribe to specific topics and tell us where to send notifications for each.
This is the list of topics you can subscribe to, and information on when the associated event gets “fired”.
Order topics
Topic | Triggered When | Payload Resource |
---|---|---|
order.created | Sent when an order is created | /api/v3/orders/:id |
order.updated | Sent when an order is updated | /api/v3/orders/:id |
order.canceled | Sent when an order is canceled | /api/v3/orders/:id |
order.completed | Sent when an order is completed | /api/v3/orders/:id/holds |
order.hold.added | Sent when a hold is added to an order | /api/v3/orders/:id/holds |
order.hold.cleared | Sent when a hold is cleared for an order | /api/v3/orders/:id/trackings |
tracking.created | Sent when tracking information is first received for an order | /api/v3/orders/:id/trackings |
tracking.delivered | Sent when tracking information indicates the order has been delivered | /api/v3/orders/:id/trackings |
tracking.updated | Sent when tracking information has been updated for an order | /api/v3/orders/:id/trackings |
Stock topics
Topic | Triggered When | Payload Resource |
---|---|---|
stock.transition | Sent when product stock moves from one state to another (e.g. an order moves 3 “in-stock” units to “reserved”) | see below |
alert.low-stock | Sent when a configured low-stock alert is triggered | see below |
alert | Sent when a generic alert is triggered | see below |
Return topics
Topic | Triggered When | Payload Resource |
---|---|---|
return.created | Sent when a return is created | /api/v3/returns/:id |
return.updated | Sent when a return is updated | /api/v3/returns/:id |
return.canceled | Sent when a return is canceled | /api/v3/returns/:id |
return.completed | Sent when a return is completed | /api/v3/returns/:id |
return.hold.added | Sent when a hold is added to a return | /api/v3/returns/:id/holds |
return.hold.cleared | Sent when a hold is cleared for a return | /api/v3/returns/:id/holds |
return.tracking.created | Sent when tracking information is first received for a return | /api/v3/returns/:id/trackings |
return.tracking.updated | Sent when tracking information has been updated for a return | /api/v3/returns/:id/trackings |
return.tracking.delivered | Sent when tracking information indicates a return has been received by the warehouse | /api/v3/returns/:id/trackings |
Receiving (ASN) topics
Topic | Triggered When | Payload Resource |
---|---|---|
receiving.created | Sent when a receiving order is created | /api/v3/receivings/:id |
receiving.updated | Sent when a receiving order is updated | /api/v3/receivings/:id |
receiving.canceled | Sent when a receiving order is canceled | /api/v3/receivings/:id |
receiving.completed | Sent when a receiving order is completed | /api/v3/receivings/:id |
receiving.hold.added | Sent when a hold is added to a receiving order | /api/v3/receivings/:id/holds |
receiving.hold.cleared | Sent when a hold is cleared for a receiving order | /api/v3/receivings/:id/holds |
receiving.tracking.created | Sent when tracking information is first received for a receiving order | /api/v3/receivings/:id/trackings |
receiving.tracking.updated | Sent when tracking information has been updated for a receiving order | /api/v3/receivings/:id/trackings |
receiving.tracking.delivered | Sent when tracking information indicates a receiving order has been received by the warehouse | /api/v3/receivings/:id/trackings |
Product topics
Topic | Triggered When | Payload Resource |
---|---|---|
product.created | Sent when a product order is created | /api/v3/product/:id |
product.updated | Sent when a product is updated | /api/v3/product/:id |
product.retired | Sent when a product is retired | /api/v3/product/:id |
POST bodies
Webhooks are POSTed to endpoints with a common envelope wrapping a topic-dependent resource. For most topics,
the resource, or “body”, is identical to the resource you would get from a related API endpoint. For example, on
a tracking.updated webhook, you might get:
{
"attempt": 1,
"body": {
"status": 200,
"message": "Successful",
"resourceLocation": "https://api.shipwire.com/trackings/638903765",
"resource": {
"id": 638903765,
"orderId": 186903450,
"orderExternalId": null,
"tracking": "294631149443923572",
"carrier": null,
"url": null,
"summary": "Shipment information sent to FedEx",
"summaryDate": "2015-05-05 03:17:10",
"trackedDate": "2015-05-05 03:17:10",
"deliveredDate": null
}
},
"timestamp": "2015-05-12T11:01:51-07:00",
"topic": "tracking.updated",
"uniqueEventID": "ba898330ad9b9dfd41de247c09bf7b96",
"webhookSubscriptionID": 222
}
The object above, rooted at “bodyâ€, is the same object that you would get from the order-tracking API. The exceptions to this pattern are “stock.transitionâ€, “alertâ€, and “alert.low-stockâ€, which contain data unique to those webhook topics, and are described below:
“stock.transition†webhook body
{
"orderId": 1244,
"productId": 528,
"warehouseId": 1038,
"fromState": "pending",
"toState": "good",
"delta": 12,
"toStateStockAfterTranstion": 24,
"fromStateStockAfterTranstion":64
}
It is important to note that the toStateStockAfterTransition and fromStateStockAfterTransition fields are meant to be references, but since webhooks may send in a different order than the actual events occurred, the latest webhook you receive may not necessarily contain the most up-to-date stock values. For correct and up-to-date information, use the Stock endpoint.
“alert†and “alert.low-stock†webhook body
{
"id": "2",
"type": "backordered",
"name": "A backordered alert",
"triggeredFor": {
"warehouseId": 1038,
"productId": 528
},
"triggerCondition": {
"type": "backordered",
"value": 1104,
"threshold": 1
}
}
Webhook versions
Currently, the Webhooks API has only the “v1†version. In the future, additional Webhook API versions will be added as needed to support new capabilities and topics to subscribe to.
If you want your integration with Shipwire to be tied to a specific version of the Webhook API which has a particular payload structure and content version, you can specify the API version as a prefix to the topic.
- "v1.order.created"
- "v1.order.updated"
- "v1.order.canceled"
- "v1.order.completed"
- "v1.order.hold.added"
- "v1.order.hold.cleared"
- "v1.tracking.created"
- "v1.tracking.updated"
- "v1.tracking.delivered"
- "v1.stock.transition"
- "v1.alert.low-stock"
- "v1.alert"
Subscribing to topics without a prefixed version number means that your integration will use the latest API payload
version at the time of subscription. For example, if you register now for the topic order.created, your subscription
will be tied to v1. After v2 is made available, your existing subscriptions will remain with v1 and that distinction will
not change. However, if you now add new subscriptions without specifying the API version, those new subscriptions will
be tied to v2. By specifying a version, you can ensure that each of your topic subscriptions are associated with the
version of the Webhook API that you want.
Guarantees and caveats
Webhooks are currently delivered on a best-effort basis. Shipwire will typically deliver a webhook message within minutes of an event occurring and usually much sooner. The message will be sent once and only once while Shipwire and your application’s servers both remain connected and available.
Requirements for webhook endpoints
Webhook recipients are expected to conform to the following:
- URLs must be for HTTPS hosts with valid and verifiable SSL certificates
- Servers must reply to POST requests with a 200-level response within 5 seconds
- Servers must reply to HEAD requests with a 200-level response within 5 seconds (HEAD requests are occasionally used to validate the endpoint, e.g. at subscription time)
When a failure occurs on a POST request to the consumer, the message will be retried. Note that the rate and number of retries is not constant.
Secrets
Verification
Webhooks should be verified by the consumer to confirm that information is authentic. Accounts which have at least one active API Secret will have webhook events with a signature for each valid secret as an HTTP header. Example:
X-Shipwire-Signature: abc123;secret-id=2
X-Shipwire-Signature: bcd345;secret-id=5
The hash value is the HMAC-SHA256 of the unaltered POST request body. Having multiple secrets allows you to rotate your keys without missing messages.
Signature verification code samples
Here is a sample of how you could verify your webhook secrets in PHP
if ($key === FALSE) {
echo "invalid key";
return;
}
$request = file_get_contents("php://input");
if (strlen($request) == 0) {
$request = file_get_contents("php://stdin");
}
echo strlen($request) . " bytes. ";
echo hash_hmac("sha256", $request, $key);
Here is a sample of how you could verify your webhook secrets in GO
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"flag"
"fmt"
"io"
"log"
"os"
)
func main() {
flag.Parse()
if flag.NArg() < 1 {
log.Fatal("need key")
}
// decode the key from hex to binary ([]byte)
key, err := hex.DecodeString(flag.Arg(0))
if err != nil {
log.Fatal(err)
}
// compute hash
h := hmac.New(sha256.New, key)
l, err := io.Copy(h, os.Stdin)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d bytes: %x\n", l, h.Sum(nil))
}
API reference
View the webhooks API reference here