Webhooks

Table of Contents

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"
}

Webhooks for order and vehicle revisions

General info

Webhooks for order and vehicle revisions allow getting notifications when an order or its vehicles are updated. Using these webhook events API users are able to fully synchronize data in their system with Shipper TMS. These events allow subscribing to any subset of field changes. For example, if you are interested only in price changes you can subscribe to the price field changes and get notified only when the order price is changed.

To subscribe order or vehicle changes use the following list of events:

  1. order.created - order is created
  2. order.modified - order is updated
  3. vehicle.created - vehicle is created
  4. vehicle.modified - vehicle is updated
  5. vehicle.deleted - vehicle is deleted

The payload for subscribing to these events accepts audit_field_set field. This field should contain the list of order or vehicle fields which values will be added to the webhook payload when it's triggered.

The triggered webhook payload has the following shape:

1
2
3
4
5
6
7
8
9
{
  "action": "<webhook_action>", // order.created, order.modified, vehicle.created, vehicle.modified, vehicle.deleted
  "order_guid": "cd04ce94-5c35-442d-b9e6-183a900b8848", //for order.created or order.modified
  "vehicle_guid": "rt04cey4-5c35-442d-b9e6-183a900b5672", //for vehicle.created, vehicle.modified, vehicle.deleted
  "revision_guid": "t50r2ey4-5c35-442d-b9e6-183a43eb5621", // revision GUID
  "action_date": "2020-11-24T11:43:37.480+0000",
  "user_guid": "42a630e3-a55f-4374-8f1a-bb16d272393d", // user GUID who performed the action
  "data": <the payload with data diffs>
}

The nested data field's shape is similar to the order's (or vehicle's) shape except instead of primitive value leaf fields contain old and new values like "field": { "old_value": <old price value>, "new_value": <new price value>}. For order.created and vehicle.created events old_value is always null. For vehicle.deleted event new_value is always null.

  • order.modified and vehicle.modified events are triggered only when one of audit_field_set fields are changed.
  • order.created, vehicle.created and vehicle.deleted events are triggered even if the audit_field_set is empty.

Subscription example for order revisions

Here is the example of how to subscribe to order's number, price, and pickup.venue.name field changes:

1
2
3
4
5
6
7
curl -X "POST" "https://api.shipper.superdispatch.com/v1/public/webhooks/order.modified/subscribe" \
     -H 'Authorization: Bearer <access_token>' \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d \$'{
  "callback_url": "<callback_url>",
  "audit_field_set": ["number", "price", "pickup.venue.name"]
}'

When these fields are changed the following payload will be sent:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "action": "vehicle.modified",
  "order_guid": "55dd0a13-7986-4bdf-97f2-9ee1ecc0f99c",
  "revision_guid": "ed92b963-161d-40eb-9311-25424acc0a00",
  "action_date": "2020-11-24T11:43:37.480+0000",
  "user_guid": "42a630e3-a55f-4374-8f1a-bb16d272393d",
  "data": {
    "number": {
      "old_value": "order #123",
      "new_value": "#456"
    },
    "price": {
      "old_value": 500.55,
      "new_value": 700.99
    },
    "pickup": {
       "venue": {
           "name": {
              "old_value": "terminal #123",
              "new_value": "terminal #456",
           }
       }
    }
  }
}

Other fields that also may have been changed with this update aren't included in the payload.

Some order fields could be changed by a carrier. In such cases, the webhook payload will contain the carrier information who made these changes. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
  "action": "order.modified",
  "order_guid": "4bb162cb-ce49-4dbb-aba4-2738b925434e",
  "revision_guid": "0c79d8b0-ee36-4d56-a71d-c20c99da8268",
  "action_date": "2020-11-24T13:52:24.780+0000",
  "carrier_phone": "+1234567890",
  "carrier_name": "Charon the Ferryman",
  "carrier_contact_name": "Charon",
  "carrier_guid": "7bec305c-13c1-4c00-a59f-06af456c8c0e",
  "carrier_email": "[email protected]",
  "data": {
    "pickup": {
      "scheduled_at_by_carrier": {
        "old_value": null,
        "new_value": "2020-11-27T15:00:00.000+0000"
      }
    },
    "delivery": {
      "scheduled_at_by_carrier": {
        "old_value": null,
        "new_value": "2020-11-28T15:00:00.000+0000"
      },
      "notes": {
        "old_value": "Meet John",
        "new_value": "Met Boris"
      }
    }
  }
}

Subscription example for vehicle revisions

Similarly, to subscribe to vehicle's make, model, and vin fields changes you can use the following command:

1
2
3
4
5
6
7
curl -X "POST" "https://api.shipper.superdispatch.com/v1/public/webhooks/vehicle.modified/subscribe" \
     -H 'Authorization: Bearer <access_token>' \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d \$'{
  "callback_url": "<callback_url>",
  "audit_field_set": ["vehicles.make", "vehicles.model", "vehicles.vin"]
}'

When these fields are changed the following payload will be sent:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "action": "vehicle.modified",
  "vehicle_guid": "55dd0a13-7986-4bdf-97f2-9ee1ecc0f99c",
  "revision_guid": "ed92b963-161d-40eb-9311-25424acc0a00",
  "action_date": "2020-11-24T11:43:37.480+0000",
  "user_guid": "42a630e3-a55f-4374-8f1a-bb16d272393d",
  "data": {
    "make": {
      "old_value": "GMC",
      "new_value": "Nissan"
    },
    "model": {
      "old_value": "Sierra",
      "new_value": "Altima"
    },
    "vin": {
      "old_value": "1G6DC5EY7B0157681",
      "new_value": "1N4AL3AP6FC197729"
    },
  }
}

The full list of order fields to which you can subscribe

  1. number
  2. purchase_order_number
  3. price
  4. transport_type
  5. inspection_type
  6. broker_fee
  7. order_instructions
  8. loadboard_instructions
  9. dispatcher_name
  10. sales_representative
  11. customer.name
  12. customer.business_type
  13. customer.address
  14. customer.city
  15. customer.state
  16. customer.zip
  17. customer.phone
  18. customer.email
  19. customer.contact_name
  20. customer.contact_title
  21. customer.contact_email
  22. customer.contact_phone
  23. customer.contact_mobile_phone
  24. payment.terms
  25. payment.method
  26. payment.notes
  27. payment.amount
  28. payment.reference_number
  29. customer_payment.terms
  30. customer_payment.method
  31. customer_payment.notes
  32. customer_payment.amount
  33. customer_payment.tariff
  34. customer_payment.deposit
  35. customer_payment.reference_number
  36. pickup.first_available_pickup_date
  37. pickup.date_type
  38. pickup.schedule_at_by_customer
  39. pickup.schedule_ends_at_by_customer
  40. pickup.scheduled_at
  41. pickup.schedule_ends_at
  42. pickup.schedule_at_by_carrier
  43. pickup.adjusted_date
  44. pickup.notes
  45. pickup.venue.name
  46. pickup.venue.business_type
  47. pickup.venue.address
  48. pickup.venue.city
  49. pickup.venue.state
  50. pickup.venue.zip
  51. pickup.venue.contact_name
  52. pickup.venue.contact_title
  53. pickup.venue.contact_email
  54. pickup.venue.contact_phone
  55. pickup.venue.contact_mobile_phone
  56. delivery.date_type
  57. delivery.schedule_at_by_customer
  58. delivery.schedule_ends_at_by_customer
  59. delivery.scheduled_at
  60. delivery.schedule_ends_at
  61. delivery.schedule_at_by_carrier
  62. delivery.adjusted_date
  63. delivery.notes
  64. delivery.venue.name
  65. delivery.venue.business_type
  66. delivery.venue.address
  67. delivery.venue.city
  68. delivery.venue.state
  69. delivery.venue.zip
  70. delivery.venue.contact_name
  71. delivery.venue.contact_title
  72. delivery.venue.contact_email
  73. delivery.venue.contact_phone
  74. delivery.venue.contact_mobile_phone

The full list of vehicle fields to which you can subscribe

  1. vehicles.make
  2. vehicles.model
  3. vehicles.type
  4. vehicles.year
  5. vehicles.color
  6. vehicles.vin
  7. vehicles.price
  8. vehicles.tariff
  9. vehicles.lot_number
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"
  }
}