Webhooks

Arta will optionally deliver webhook events to your HTTP webhook endpoints at key moments during the fulfillment workflow for request and shipment resources. These webhooks can be used to build your own custom notifications, which might include email, SMS, push notifications, or onsite alerts.  Webhooks are also useful for keeping any cached data in sync with Arta’s resources.


API Reference

View the Webhook endpoints on Arta’s API Reference site.


Webhook schema

Every webhook payload is comprised of three main parts:

  • data — a representation of the updated resource
    • For request resources the schema is identical to the retrieve request API endpoint
    • For shipment resources the schema is identical to the retrieve shipment API endpoint
  • object — the name of the resource type; at present the value will always be either request or shipment
  • type — a label describing the type of webhook being sent

Webhook Delivery Types

  • Ping (ping) – A ping message event has been delivered to the webhook endpoint.
  • Request Created (request.created) – The request has been created.
  • Request Shared (request.shared) – The request has been shared.
  • Request Status Updated (request.status.updated) – The request’s status has changed.
  • Request Updated (request.updated) – The request’s details have changed.
  • Shipment Created (shipment.created) – A shipment has been booked from a quote on a request.
  • Shipment EEI Form Status Updated (shipment.eei_form_status.updated) – The shipment’s eei_form_status has changed.
  • Shipment Exceptions Updated (shipment.exceptions.updated) – The shipment’s exceptions has changed.
  • Shipment Schedule Updated (shipment.schedule.updated) – The shipment’s collection and/or delivery schedule have been updated.
  • Shipment Status Updated (shipment.status.updated) – The shipment’s status has changed.
  • Shipment Tracking Updated (shipment.tracking.updated) – Tracking details for a package in the shipment has been added or changed.
  • Shipment Updated (shipment.updated) – The shipment’s details have changed.
  • Shipment Exception Created (shipment_exception.created) – The shipment exception has been created.
  • Shipment Exception Status Updated (shipment_exception.status.updated) – The shipment exception’s status has been updated.

Retries

Arta’s webhook delivery system expects a 2xx HTTP status code in response to receiving the event to indicate the event’s successful receipt. If your endpoint returns any other status code during a delivery, Arta will retry sending the event with exponential backoff in both live and test modes.

Enabling and Disabling

Manual disabling

Webhook endpoints may be manually paused in the Arta Sellers Dashboard. When an endpoint is paused, Arta will not attempt to deliver any events to the endpoint. This is useful when you need to temporarily disable an endpoint, such as during maintenance or when you are debugging your integration.

To manually disable an endpoint,

  • click on the “Developers” tab in the sidebar navigation of the Arta Sellers Dashboard
  • click on the “Webhook Endpoints” link in the sidebar navigation; this will open the webhook endpoints list view which presents all your webhook endpoints for the current “live” or “test mode” environment along with their current statuses
  • click on the webhook endpoint you would like to disable; this will open the endpoint’s detail view
  • click on the “actions” dropdown in the top right corner of the endpoint’s detail view and select “Disable”; you should now see that the status of the endpoint has been updated to “Disabled”

To re-enable the endpoint at any time, you can click the “Enable” link in the actions menu on this same page.

Automatic disabling

Arta will automatically disable an endpoint if the endpoint hasn’t responded with a 2xx HTTP status code for multiple days in a row. In this case, the status of the endpoint will be updated to “Error” and the Sellers Dashboard will display a message indicating that the endpoint will be disabled after a certain date. If the webhook endpoint resumes returing successful 2xx HTTP status codes with their responses, the status will automatically be updated to “Enabled”. If the endpoint has been automatically disabled, you can manually re-enable it at any time in the Sellers Dashboard.

In advance of this automatic disabling, Arta will also attempt to notify all organization owners by email. The email will state when the endpoint will be automatically disabled.

Verifying webhooks

Arta delivers each webhook event with an Arta-Signature HTTP header. This enables you to verify that the events were sent by Arta, not by a third party.

Before you can verify signatures, you need to retrieve your webhook endpoint’s secret from the “get a webhook secret token” API endpoint or via the webhook endpoint’s detail page in the Arta Dashboard. Arta generates a unique secret token for each endpoint.

You may optionally generate a new secret token with the “reset a webhook secret token” endpoint or from within the Dashboard at any point. Note that changing the secret token will immediately cause future webhook events to use the newly generated token.

The Arta-Signature header included in each webhook delivery contains a timestamp and a signature. The timestamp is prefixed by t=, and the signature is prefixed with s=.

The following is an example header:

Arta-Signature: t=1623359782,s=j+WrZkH4UyzFXlgC3UsuRfnvYjeovCcAZPdKnG41sj4=

Arta generates signatures using a hash-based event authentication code (HMAC) with SHA-256. The signature is then Base64 encoded when sent with the webhook.

The step-by-step guide below describes how to prepare and verify each event.

Step 1: Extract the timestamp and signatures from the header

Split the header, using the , character as the separator, to get a list of elements. Then split each element, using the = character as the separator, to get a prefix and value pair.

The value for the prefix t corresponds to the timestamp, and s corresponds to the signature.

Step 2: Prepare the signed_payload string

The signed_payload string is created by concatenating:

  • The timestamp (as a string)
  • The character .
  • The actual JSON payload (i.e., the request body)

Step 3: Determine the expected signature

Compute an HMAC with the SHA256 hash function. Use the webhook endpoint’s secret token as the key, and use the signed_payload string as the event.

Then Base64 encode the HMAC to complete generation of the expected signature.

Step 4: Compare the signatures

Compare the signature (or signatures) in the header to the expected signature.

Additionally, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance.

Example verification implementations

The next section provides reference verification implementations in a few different programming languages. Each implementation assumes that a webhook event is received with the following Arta-Signature header and event body:

# Webhook Arta-Signature header
t=1623359782,s=Hau27QgzVq3vr+ocQSx5bxoX1TLdz0IhcvGdBdvgsjg=
# Webhook event body
{\"data\":{\"id\":134},\"object\":\"webhook\",\"type\":\"ping\"}

As well, the associated webhook’s secret token was retrieved from the “get a webhook secret token” API endpoint and had the following value:

2jjKqld6rjlUcl8pRB4mCM6hQrCuQ2GTGvp_otzQHGjpKYJ1-0AD3yToE2cKk25e

Using Elixir

# Retrieved via the Arta API /webhooks/:id/secret_token endpoint
secret = "2jjKqld6rjlUcl8pRB4mCM6hQrCuQ2GTGvp_otzQHGjpKYJ1-0AD3yToE2cKk25e"

# Received via the webhook's Arta-Signature header
signature = "Hau27QgzVq3vr+ocQSx5bxoX1TLdz0IhcvGdBdvgsjg="

# Prepare the expected signed_payload in the `TIMESTAMP.PAYLOAD` format
signed_payload = "1623359782.{\"data\":{\"id\":134},\"object\":\"webhook\",\"type\":\"ping\"}"

# Generate the expected Base64 encoded hmac
expected = :crypto.mac(:hmac, :sha256, secret, signed_payload) |> Base.encode64()

# Validate that the expected signature matches the signature you received
IO.inspect(expected == signature)

Using Ruby

require 'base64'
require 'openssl'

# Retrieved via the Arta API /webhooks/:id/secret_token endpoint
secret = "2jjKqld6rjlUcl8pRB4mCM6hQrCuQ2GTGvp_otzQHGjpKYJ1-0AD3yToE2cKk25e"

# Received via the webhook's Arta-Signature header
signature = "Hau27QgzVq3vr+ocQSx5bxoX1TLdz0IhcvGdBdvgsjg="

# Prepare the expected signed_payload in the `TIMESTAMP.PAYLOAD` format
signed_payload = "1623359782.{\"data\":{\"id\":134},\"object\":\"webhook\",\"type\":\"ping\"}"

# Generate the expected Base64 encoded hmac
hmac = OpenSSL::HMAC.digest("SHA256", secret, signed_payload)
expected = Base64.strict_encode64(hmac)

# Validate that the expected signature matches the signature you received
print expected == signature

Using Python

import hashlib
import hmac
import base64

# Retrieved via the Arta API /webhooks/:id/secret_token endpoint
secret = bytes('2jjKqld6rjlUcl8pRB4mCM6hQrCuQ2GTGvp_otzQHGjpKYJ1-0AD3yToE2cKk25e', 'utf-8')

# Received via the webhook's Arta-Signature header
signature = bytes('Hau27QgzVq3vr+ocQSx5bxoX1TLdz0IhcvGdBdvgsjg=', 'utf-8')

# Prepare the expected signed_payload in the `TIMESTAMP.PAYLOAD` format
signed_payload = bytes('1623359782.{\"data\":{\"id\":134},\"object\":\"webhook\",\"type\":\"ping\"}', 'utf-8')

# Generate the expected Base64 encoded hmac
hash = hmac.new(secret, signed_payload, hashlib.sha256)
expected = base64.b64encode(hash.digest())

# Validate that the expected signature matches the signature you received
print(signature == expected)