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.

The verification_token field is utilized to confirm that webhook notifications received by API clients are sent by Super Dispatch.

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:

FieldTypeDescription
actionstringThe action name like order.created. See the list below.
action_datestringThe date and time when the action happened.
error_messagestringThe 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 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, only works for shipper->carrier flow)

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.

ActionIs sent when…
order.createdOrder is created
order.cancelOrder is canceled by shipper
order.submitted_by_customerOrder is submitted to shipper by customer
order.picked_upOrder is picked up
order.picked_up.ignoredOrder with active offer is manually marked as delivered, then it is picked up by the carrier
order.deliveredOrder is delivered
order.delivered.ignoredOrder with active offer is manually marked as delivered, then it is delivered by the carrier
order.picked_up_bolTriggered when pickup BOL becomes available
order.delivered_bolTriggered when delivery BOL becomes available
order.paidShipper marks order paid to carrier
order.unmark_as_paidShipper unmarks order as paid to carrier
order.customer_paidOrder is marked as paid by customer
order.invoicedOrder is invoiced by the carrier
order.customer_invoicedOrder is invoiced to the customer
order.archivedOrder is archived
order.marked_as_on_holdOrder is marked as on hold by shipper
order.unmarked_as_on_holdOrder is unmarked as on hold by shipper
order.unarchivedOrder is unarchived
order.posted_to_cdOrder is posted to Central Dispatch
order.removed_from_cdOrder is removed (unposted) from Central Dispatch
order.posted_to_slbOrder is posted to Super Loadboard (SLB)
order.removed_from_slbOrder is removed (unposted) from SLB
order.bookedOrder is booked by a preferred carrier via SLB
order.manually_marked_as_newOrder is manually marked as new
order.manually_marked_as_pendingOrder is manually marked as pending
order.manually_marked_as_acceptedShipper manually marks order as accepted
order.manually_marked_as_invoicedShipper manually marks order as invoiced by carrier
order.manually_unmarked_as_invoicedShipper manually unmarks order as invoiced by carrier
order.manually_marked_as_picked_upOrder is manually marked as picked up
order.manually_marked_as_deliveredOrder is manually marked as delivered
order.rolled_back_manual_status_changeOrder status is manually rolled back
order.removedOrder is removed
order.restoredOrder is restored

The order payload has only one additional field:

Field nameTypeDescription
order_guidguidGUID of the related order

Samples:

order.created is triggered when order is created.

1
2
3
4
5
{
  "action": "order.created",
  "action_date": "2019-10-31T05:23:15.835+0000",
  "order_guid": "cd04ce94-5c35-442d-b9e6-183a900b8848"
}

order.picked_up_bol webhook event is triggered only when pdf_bol_url and online_bol_url become available, which indicates that the pickup inspection synchronization is finished.

1
2
3
4
5
6
7
{
  "action": "order.picked_up_bol",
  "order_guid": "d2be393a-c3a0-4680-bbb9-d6fa84aa2d4c",
  "action_date": "2021-02-24T09:49:37.051+0000",
  "pdf_bol_url": "https://carrier.superdispatch.com/orders/pdf-bol/Kkryz1y8QYpmdeR1q7bde/",
  "online_bol_url": "https://bol.superdispatch.com/KRyz1y8QYpmdeqm73WR1q7bde"
}

order.delivered_bol webhook event is triggered only when pdf_bol_url, online_bol_url and pdf_delivery_receipt_url become available, which indicates that the delivery inspection synchronization is finished.

1
2
3
4
5
6
7
8
{
  "action": "order.delivered_bol",
  "order_guid": "d2be393a-c3a0-4680-bbb9-d6fa84aa2d4c",
  "action_date": "2021-02-24T09:58:33.544+0000",
  "pdf_bol_url": "https://carrier.superdispatch.com/orders/pdf-bol/KRyz1y8QYpmdeqm73WR1q7bde/",
  "online_bol_url": "https://bol.superdispatch.com/KRyz1y8QYpmdeqm73WR1q7bde",
  "pdf_delivery_receipt_url": "https://carrier.superdispatch.com/orders/Kkryz1y8QYpmdeR1q7bde/delivery-receipt/pdf/"
}

order.submitted_by_customer webhook event is triggered when customer submits order from the customer portal or via shipper-to-broker flow. This event has customer_counterparty_guid that indicates which customer submitted the order:

1
2
3
4
5
6
{
  "action": "order.submitted_by_customer",
  "order_guid": "d2be393a-c3a0-4680-bbb9-d6fa84aa2d4c",
  "action_date": "2021-02-24T09:58:33.544+0000",
  "customer_counterparty_guid": "4f797316-63a8-432a-a4ef-2986b8occ89d"
}

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
22
{
  "action": "vehicle.modified",
  "order_guid": "55dd0a13-7986-4bdf-97f2-9ee1ecc0f99c",
  "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
ActionIs sent when…
offer.sentLoad offer is sent
offer.sent.failedSending a load offer is failed
offer.acceptedLoad offer is accepted by carrier
offer.accepted.ignoredThe carrier accepts the load offer after it was manually marked as picked up or delivered by the shipper
offer.updated_to_acceptedThe carrier has reverted the order status from picked_up to new
offer.updated_to_accepted.ignoredThe carrier has reverted the order status from delivered to new, or from delivered to picked_up to new
offer.declinedLoad offer is declined
offer.declined.ignoredThe carrier declines the load offer after it was manually marked as delivered by the shipper
offer.canceledLoad offer is canceled by shipper
offer.canceled_by_carrierLoad offer is canceled by carrier
offer.canceled_by_carrier.ignoredLoad offer is canceled by carrier after it was delivered

The offer payload has these additional fields:

Field nameTypeDescription
offer_guidguidGUID of the load offer
order_guidguidGUID of the related order
carrier_guidguidGUID of the carrier which the load offer was sent to
statusstringThe order status.
idbigintUnique identifier (primary key) of the load offer. This is deprecated.
order_idbigintUnique 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"
}
ActionIs sent when…
load_request.createdCarrier sends a load request to shipper
load_request.updatedCarrier updates their own request (e.g. price, pickup or devliery dates, etc.)
load_request.canceled_by_carrierCarrier cancels their own request
load_request.declined_by_shipperShipper declines carrier’s load request

The load request payload has these additional fields:

Field nameTypeDescription
order_guidguidGUID of the related order
data.guidguidGUID of the load request
data.requested_pricenumberThe carrier suggested price
data.pickup_datedate-timeThe carrier suggested pickup date
data.delivery_datedate-timeThe carrier suggested delivery date
data.carrier_guidguidGUID of the carrier who sent the load request
data.carrier_emailstringCarrier’s email
data.carrier_phonestringCarrier’s phone number
data.carrier_namestringCarrier’s business name
data.carrier_contact_namestringCarrier’s contact person’s name
data.carrier_addressstringCarrier’s address
data.carrier_citystringCarrier’s city
data.carrier_statestringCarrier’s state
data.carrier_zipstringCarrier’s ZIP
data.carrier_usdotstringCarrier’s USDOT

Sample payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "action": "load_request.created",
  "order_guid": "823b7436-40d6-4039-bfe6-c7d90bd8c14d",
  "action_date": "2020-01-20T09:33:21.266+0000",
  "data": {
    "guid": "u789102t-f59k-j893-bfe6-c7d90bd8790f",
    "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"
  }
}

The payload above is similar for load request actions such as load_request.declined_by_shipper, load_request.canceled_by_carrier, load_request.created or load_request.updated.