Clarification on Tracking Status Updates via Webhook or GraphQL API

We are currently working on synchronizing shipment tracking statuses from ShipHero into our system, and I would like to confirm the recommended approach.

Based on the ShipHero Developer documentation and Community discussions, my current understanding is as follows:

  1. The Shipment Update webhook is triggered when a shipment is created / an order is fulfilled or shipped. However, I could not find confirmation that this webhook is triggered again when a carrier tracking status changes,

for example: IN_TRANSIT → OUT_FOR_DELIVERY → DELIVERED

Could you confirm whether a change to shipping_labels.tracking_status triggers the Shipment Update webhook?

  1. I found that the current tracking status can be retrieved through the GraphQL Shipment query, for example:

query {

    shipment(id: “shipment_id”) {

                    data {

                                    shipping_labels {

                                                    id

                                                    tracking_number

                                                    tracking_status

                                                    delivered

                                                    picked_up

                                                    carrier

                                                    tracking_url

                                    }

                            }

    }

}

If tracking status changes do not trigger a webhook, is periodically querying the Shipment API the recommended method for keeping tracking statuses synchronized?

  1. Could you also clarify how ShipHero receives tracking status updates from carriers?

For example, are tracking updates pushed from carriers to ShipHero through carrier webhooks, periodically retrieved by ShipHero through carrier APIs, or does the mechanism vary depending on the carrier?

We found documentation indicating that some carrier integrations, such as UPS, provide automated tracking updates through the carrier API, but we could not find documentation describing the general synchronization mechanism or frequency.

  1. Is there a standard or typical refresh interval for carrier tracking updates in ShipHero?

We found a Community discussion mentioning that ShipHero webhooks may sometimes take up to approximately 15 minutes to be delivered, but my understanding is that this refers to webhook delivery latency rather than the frequency at which ShipHero refreshes carrier tracking statuses. Please correct us if this understanding is incorrect.

  1. If polling the Shipment API is the recommended approach, is there a recommended polling interval or API pattern for this use case?

Our current idea would be to periodically query only active shipments whose tracking status is not yet DELIVERED and stop polling once the shipment reaches its final status.

If there is a webhook, API endpoint, bulk query, or another more efficient approach specifically designed for tracking status synchronization, please let us know.

Our primary goal is to keep our internal WMS tracking status synchronized with ShipHero while minimizing unnecessary API calls and GraphQL complexity/token usage.

Please let us know if any of the assumptions above are incorrect and what architecture ShipHero recommends for this use case.

Hi @fnsusa! I hope you are doing well!

Webhook: Shipment Update fires only on fulfillment not on tracking status changes, and there’s no separate tracking webhook. So no push updates as the shipment moves toward delivery.

The field: tracking_status lives on each ShippingLabel (not the shipment). A multi-package shipment can have multiple labels, each with its own status.

Workaround: if your carrier supports public tracking lookups (e.g. UPS, USPS work with just the tracking number, no account needed), query the carrier directly using the tracking_number you already get from the webhook, it’s faster and cuts us out of the loop. If your carrier requires the account that generated the label (common with FedEx or 3PL accounts), you’ll need to poll us instead. Note that the shipment query in your example only takes id, to look up by tracking number use shipments instead:

query {
  shipments(tracking_number: "1Z999AA10123456784") {
    data {
      edges {
        node {
          shipping_labels {
            tracking_status
            delivered
          }
        }
      }
    }
  }
}

Poll only shipments not yet in a final state, and stop once they hit one.

Recommended architecture for your WMS sync

Since no webhook fires on tracking transitions, polling the API is the correct approach, and your proposed design matches what ShipHero itself does internally:

  • Capture the Shipment Update webhook to learn about new shipments/labels immediately (shipment ID, tracking numbers).
  • Poll only shipments whose labels are not in a final state (DELIVERED, plus consider FAILURE/RETURNED as terminal).
  • Stop polling on final status; also stop after ~2 weeks as a safety valve (ShipHero itself stops refreshing after the label ages out of the 1-week scheduler window, so older statuses won’t change).

Polling faster than ~hourly buys you nothing, the underlying data refreshes on roughly that cadence. Every 1-4 hours is a sensible interval.

Best regards, Luciano!