Verifying Authenticity

FastBound digitally signs every event sent to your webhook URL with a hash-based message authentication code (HMAC), which is is a message authentication code (MAC) involving a cryptographic hash function and a secret key. The computed HMAC can be used to simultaneously verify both the integrity and the authenticity of the event.

When a new webhook is added to a FastBound account, FastBound returns a random, 256-bit secret key. If you want to verify webhooks’ authenticity coming from FastBound, you must save this secret as you will not be able to retrieve it later.

Webhooks can only be delivered to HTTPS URLs and the URL must be unique per FastBound account. In other words, if you want to receive more than one event at the same Webhook URL, your webhook must subscribe to more than one event.

Verifying Authenticity

When a subscribed event occurs in FastBound, FastBound will send an HTTP POST request to your app, with a JSON-formatted message body. The request will contain an X-Fastbound-Signature header.

To verify the signature sent by FastBound:

  1. Prepend the JSON payload with the timestamp (t) and a period (ASCII 46, 0x2E)

  2. Compute an HMAC-SHA256 hash using the secret key returned at the time the webhook was created

Note: JSON libraries vary greatly. You should compute the signature on the raw bytes received in the POST body. Computing a signature on a JSON object after it has passed through a serializer may result in a different hash and verification of the signature will fail.

Example

If you paste the following values into an HMAC-SHA256 tool like https://www.stupidtools.net , you will be able to compute the same signature

Example Key

4pUkLdAvI4CzJbKZcJoNM2VIE86ItLn4

Example Headers

POST /webhooks HTTP/1.1
Content-Length: 2080
Content-Type: application/json
X-FastBound-Signature: t=1610834911,v1=fe21f400de69f00ef9c65e95eaa6e308766261d292ed981f1d1b5ad41dc8ac97

Key

Value

t

UNIX timestamp in seconds when the Webhook event was created

v1

HMAC-SHA256 signature of the JSON payload in the POST request.

Note: The signature (v1) is 256-bits (32 bytes), encoded in hexadecimal (aka base 16 or hex), resulting in 64 bytes.

Example Plain Text / Message

Note: The timestamp and period has been prepended to the original JSON body. The timestamp and period will NOT be in the body of the webhook.

1610834911.{"id":"31cee3bf-2abe-466d-bb73-65129edd1ebd","eventName":"item.edited","accountNumber":75114,"timestampUtc":"2021-01-16T22:08:31.367926Z","data":{"dispositionType":null,"dispose_Date":null,"dispose_License":null,"dispose_LicenseName":null,"dispose_LicenseExpires":null,"dispose_TradeName":null,"dispose_Organization":null,"dispose_FirstName":null,"dispose_MiddleName":null,"dispose_LastName":null,"dispose_Address1":null,"dispose_Address2":null,"dispose_City":null,"dispose_State":null,"dispose_Postal":null,"dispose_Country":null,"dispose_PhoneNumber":null,"dispose_Fax":null,"dispose_EmailAddress":null,"ttsn":null,"otsn":null,"dispose_PurchaseOrderNumber":null,"dispose_InvoiceNumber":null,"dispose_ShipmentTrackingNumber":null,"submissionDate":null,"theftLoss_DiscoveredDate":null,"theftLoss_Type":null,"theftLoss_ATFIssuedIncidentNumber":null,"theftLoss_PoliceIncidentNumber":null,"destroyed_Date":null,"destroyed_Description":null,"destroyed_Witness1":null,"destroyed_Witness2":null,"deleteType":null,"deleteNote":null,"acquisitionType":"Purchase","acquire_Date":"2018-06-11T21:11:00","acquire_License":null,"acquire_LicenseName":null,"acquire_LicenseExpires":null,"acquire_TradeName":null,"acquire_Organization":null,"acquire_FirstName":"Ben","acquire_MiddleName":null,"acquire_LastName":"Bacon","acquire_Address1":"2333 Black Oak Hollow Road","acquire_Address2":null,"acquire_City":"Sunnyvale","acquire_State":"CA","acquire_Postal":"94089","acquire_Country":null,"acquire_PhoneNumber":null,"acquire_Fax":null,"acquire_EmailAddress":null,"acquire_PurchaseOrderNumber":"PO","acquire_InvoiceNumber":"INVOICE","acquire_ShipmentTrackingNumber":"SHIPMENT","undeleteNote":null,"id":"440234a7-8bc1-45b5-bea2-a8fd00440b55","externalId":null,"itemNumber":"00001","status":2,"statusText":"Pending Disposal","manufacturer":"GLOCK","countryOfManufacture":"AUSTRIA","importer":"GLOCK INC","type":"Pistol","model":"17","caliber":"9MM","serial":"AAB1142","barrelLength":null,"overallLength":null,"condition":null,"location":null,"cost":null,"price":null,"mpn":null,"upc":null,"sku":null}}