Webhooks

Super Dispatch uses webhooks to update an API client when various events (or actions) happen on the platform. An API client should subscribe to an action to receive updates and unsubscribe to stop it. All webhook requests are POST requests with a JSON payload. All endpoints, request and response details are available in the API reference: webhooks.

You can see the diagram that explains when a webhook event is triggered in the document Flows.

Managing webhook subscriptions

The list of available webhook actions can be retrieved using the specific API endpoint: Get the list of all webhook actions. Deprecated webhook actions aren't returned.

The API client can subscribe to a webhook action by providing a callback URL (reference):

1
2
3
4
5
6
curl -X "POST" "https://api.shipper.superdispatch.com/v1/public/webhooks/<webhook_action>/subscribe" \
     -H 'Authorization: Bearer <access_token>' \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d \$'{
  "callback_url": "<callback_url>"
}'

The response is a confirmation of the subscription:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "status": "success",
  "data": {
    "object": {
      "is_active": true,
      "created_at": "2019-11-19T21:44:57.979+0000",
      "changed_at": "2019-11-19T21:44:57.979+0000",
      "action": "<webhook_action>",
      "verification_token": "87be7a34-238d-4378-bda9-4d93ffe50982",
      "callback_url": "<callback_url>",
      "guid": "9ea8edaf-874b-4dee-8be7-29ab169a21ea"
    }
  }
}

After a successful subscription, Super Dispatch starts sending POST requests to the provided callback URL when the webhook action happened (like order.picked_up or order.archived). For example, if the API client is subscribed to the order.created webhook action, the API server sends a request whenever a new order is created on Shipper TMS: via the API or manually on the user interface.

You can unsubscribe from a webhook action (reference):

1
2
curl -X "POST" "https://api.shipper.superdispatch.com/v1/public/webhooks/<webhook_action>/unsubscribe" \
     -H 'Authorization: Bearer <access_token>'

The list of current webhook subscriptions can be retrieved (reference):

1
2
curl -X "GET" "https://api.shipper.superdispatch.com/v1/public/webhooks" \
     -H 'Authorization: Bearer <access_token>'

Payload

The payload (request body) always contains these default fields:

Field Type Description
action string The action name like order.created. See the list below.
action_date string The date and time when the action happened.
error_message string The error message (is sent when a previous action is failed).

The payload also contains the target object guid like order_guid or offer_guid.

Retry policy

The webhook request timeout is 10 seconds. The API client that is subscribed to a webhook action should return a 2xx response in 60 seconds. Otherwise, the webhook request is failed with timeout. Furthermore, an HTTP response codes like 3xx, 4xx, and 5xx fail the webhook request.

The retry policy is linear:

  • interval: 60 seconds
  • retry count: 5.

This means when the API received a failed response from the callback URL, it'll send 5 requests with 60 seconds of interval until it gets a successfull response. It stops sending a request after 5th try.

Testing webhooks

We suggest to use webhook.site during the implementation process to test the delivery and payload of webhook requests.

Actions

The actions supported by the Shipper API are below.

ignored actions

We also send .ignored webhook actions when a carrier updates the order which status is already delivered or archived on the Shipper TMS. These updates are ignored by default, but the corresponding events are sent to API clients to inform them that the carrier actually changed the order status.

Here's a quick explanation:

  1. A load offer is sent to a carrier (offer.sent is sent)
  2. The load offer is accepted by the carrier (offer.accepted is sent)
  3. The corresponding order is manually marked as picked up on Shipper TMS (order.manually_marked_as_picked_up is sent)
  4. The order is manually marked as delivered on Shipper TMS (order.manually_marked_as_delivered is sent)
  5. Then the order is marked as picked up on Carrier TMS (order.picked_up.ignored is sent)

It is done to avoid confusion and inconsistencies in order statuses. For instance, if order with an active offer is manually marked as picked up and then as delivered prior to the carrier making any actions, an API client receives order.manually_marked_as_picked_up and order.manually_marked_as_delivered. If we sent order.picked_up after carrier picks up the order, it would confuse an API client to be informed about their delivered order being picked up again.

Action Is sent when…
order.created Order is created
order.cancel Order is canceled by shipper
order.submitted_by_customer Order is submitted to shipper by customer
order.picked_up Order is picked up
order.picked_up.ignored Order with active offer is archived or manually marked as delivered, then it is picked up by the carrier
order.delivered Order is delivered
order.delivered.ignored Order with active offer is archived or manually marked as delivered, then it is delivered by the carrier
order.paid Shipper marks order paid to carrier
order.unmark_as_paid Shipper unmarks order as paid to carrier
order.customer_paid Order is marked as paid by customer
order.invoiced Order is invoiced by the carrier
order.customer_invoiced Order is invoiced to the customer
order.archived Order is archived
order.marked_as_on_hold Order is marked as on hold by shipper
order.unmarked_as_on_hold Order is unmarked as on hold by shipper
order.unarchived Order is unarchived
order.posted_to_cd Order is posted to Central Dispatch
order.removed_from_cd Order is removed (unposted) from Central Dispatch
order.posted_to_slb Order is posted to Super Loadboard (SLB)
order.removed_from_slb Order is removed (unposted) from SLB
order.booked Order is booked by a preferred carrier via SLB
order.manually_marked_as_new Order is manually marked as new
order.manually_marked_as_pending Order is manually marked as pending
order.manually_marked_as_accepted Shipper manually marks order as accepted
order.manually_marked_as_invoiced Shipper manually marks order as invoiced by carrier
order.manually_unmarked_as_invoiced Shipper manually unmarks order as invoiced by carrier
order.manually_marked_as_picked_up Order is manually marked as picked up
order.manually_marked_as_delivered Order is manually marked as delivered
order.rolled_back_manual_status_change Order status is manually rolled back
order.removed Order is removed
order.restored Order is restored

The order payload has only one additional field:

Field name Type Description
order_guid guid GUID of the related order

Sample:

1
2
3
4
5
{
  "action": "order.created",
  "action_date": "2019-10-31T05:23:15.835+0000",
  "order_guid": "cd04ce94-5c35-442d-b9e6-183a900b8848"
}
Action Is sent when…
offer.sent Load offer is sent
offer.sent.failed Sending a load offer is failed
offer.accepted Load offer is accepted by carrier
offer.accepted.ignored The carrier accepts the load offer after it was manually marked as picked up or delivered by the shipper
offer.updated_to_accepted The carrier has reverted the order status from picked_up to new
offer.updated_to_accepted.ignored The carrier has reverted the order status from delivered to new, or from delivered to picked_up to new
offer.declined Load offer is declined
offer.declined.ignored The carrier declines the load offer after it was manually marked as delivered by the shipper
offer.canceled Load offer is canceled

The offer payload has these additional fields:

Field name Type Description
offer_guid guid GUID of the load offer
order_guid guid GUID of the related order
carrier_guid guid GUID of the carrier which the load offer was sent to
status string The order status.
id bigint Unique identifier (primary key) of the load offer. This is deprecated.
order_id bigint Unique identifier (primary key) of the related order. This is deprecated.

Sample payload:

1
2
3
4
5
6
7
8
{
  "action": "offer.sent",
  "action_date": "2019-10-31T05:23:15.835+0000",
  "offer_guid": "ca252a6f-dee1-4741-bbe6-4a904fee4a1e",
  "order_guid": "cd04ce94-5c35-442d-b9e6-183a900b8848",
  "carrier_guid": "ebbfa8f0-38e2-49e4-9c72-0476f6fa878f",
  "status": "new"
}
Action Is sent when…
load_request.created Carrier sends a load request to shipper
load_request.canceled_by_carrier Carrier cancels their own request
load_request.declined_by_shipper Shipper declines carrier's load request

The load request payload has these additional fields:

Field name Type Description
order_guid guid GUID of the related order
carrier_guid guid GUID of the carrier who sent the load request
carrier_email string Carrier's email
carrier_phone string Carrier's phone number
carrier_name string Carrier's business name
carrier_contact_name string Carrier's contact person's name
carrier_address string Carrier's address
carrier_city string Carrier's city
carrier_state string Carrier's state
carrier_zip string Carrier's ZIP
carrier_usdot string Carrier's USDOT

Sample payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{
  "action": "load_request.created",
  "order_guid": "823b7436-40d6-4039-bfe6-c7d90bd8c14d",
  "action_date": "2020-01-20T09:33:21.266+0000",
  "data": {
    "carrier_guid": "9b9fd584-800c-445d-81cb-c951daaeebcf",
    "carrier_email": "[email protected]",
    "carrier_phone": "+99890909099",
    "carrier_name": "TEST Carrier Inc",
    "carrier_contact_name": "Lyubov Korovina",
    "carrier_address": "111 Texas Avenue\r\nAustin, TX 48034",
    "carrier_city": "Austin",
    "carrier_state": "TX",
    "carrier_zip": "48034",
    "carrier_usdot": "3942812",
    "requested_price": "12",
    "pickup_date": "2020-11-20T10:33:29.112+0000",
    "delivery_date": "2020-11-20T10:33:29.112+0000"
  }
}