Time in Transit API for UPS, FedEx, USPS and DHL
A time in transit request asks a carrier when a shipment sent today (or on a date you choose) from one postal code to another would arrive, for each service it offers on that lane. It returns delivery dates, not prices. Use it for an "arrives by Thursday" promise at checkout, to pick the cheapest service that still makes a deadline, or to check a lane before you promise anything.
In RocketShipIt every carrier takes the same request. The action is
timeintransit, the origin goes in ship_*, and the destination goes in
to_*:
{
"carrier": "UPS-REST",
"action": "timeintransit",
"params": {
"key": "your-key-from-authenticate-request",
"ship_city": "Whitehall",
"ship_state": "MT",
"ship_code": "59759",
"ship_country": "US",
"to_code": "90210",
"to_country": "US",
"pickup_date": "2026-01-15"
}
}
Every carrier returns the same response shape: one entry per service, each with its delivery date.
{
"data": {
"errors": [],
"services": [
{
"desc": "UPS Next Day Air Early",
"service_code": "1DM",
"is_guaranteed": true,
"eta": 1768550400,
"formatted_eta": "Fri January 16 by 08:00 am",
"delivery_days": 1
}
]
}
}
The fields are listed under TimeInTransit.
The raw carrier reply is in transactions[].response, the same as for every
other action.
Do you need a separate call?#
Often you don't. If you are rating anyway, the rates already carry transit
times for the major carriers. UPS-REST rates with request_option set to
Shoptimeintransit by default, and FedEx-REST and DHL-REST return their
estimates with each rate, so delivery_days and est_delivery_time arrive on
every rate in one call (see Rating).
A separate timeintransit call is worth it when:
- you want dates without prices, for example on a product page before there is a cart to rate
- you want USPS delivery standards, which USPS serves from a separate API
- you want UPS's guarantee and Saturday delivery flags per service without rating
One catch when you mix the two: UPS time-in-transit service codes are not
rate service codes. Time in transit returns service level codes
such as 1DM, 2DA and GND, while rating uses 14, 03. If you join the
two responses, map them yourself, or take the transit time from the rate
response and skip the mapping.
Carrier support#
| Carrier | carrier value |
Needs | Returns |
|---|---|---|---|
| UPS | UPS-REST |
origin and destination postal code and country; city for international | date and time, business days, guarantee, Saturday delivery |
| FedEx | FedEx-REST |
origin and destination postal code and country | date, transit days |
| USPS | USPS-REST |
origin and destination ZIP code | date and time per mail class |
| DHL Express | DHL |
origin and destination postal code and country | date and time per product |
The legacy UPS, FedEx and USPS (Web Tools) carriers also implement
timeintransit, but those carrier APIs are being retired. See
carrier API retirement dates before
you build on them. DHL-REST and OnTrac-REST have no separate call; their
estimates come back with each rate.
Choosing the ship date#
The ship date is the day the carrier gets the package, not the day the order is placed. It moves every estimate, so set it once you know it.
- UPS-REST reads
pickup_dateinYYYY-MM-DDformat and defaults to today. It does not readship_date, and it passespickup_dateto UPS unchanged, so20260115is sent as it is rather than converted. UPS accepts dates up to 60 days ahead and 35 days back. - FedEx-REST reads
pickup_dateorship_date, inYYYY-MM-DD,YYYYMMDDor RFC3339 format, and defaults to today. - USPS-REST sends no date. The estimate is for mail entered today.
- DHL reads
pickup_date(YYYY-MM-DD) andready_time(HHMM). The ready time defaults to one hour from now, and DHL rejects dates more than about 10 days ahead.
UPS#
UPS returns the most detail: the service description, the UPS service level
code, delivery date and time, delivery_days (business days in transit),
is_guaranteed, and saturday_delivery when the service delivers on
Saturday on that lane.
Things to know:
- UPS filters its own list. By default it drops US domestic services that are slower than UPS Ground on the lane. If Ground arrives in two days, you won't see 3 Day Select. This is the same rule that hides services on rate requests.
- International needs a city on both ends. If you leave
to_cityempty, RocketShipIt fills it in from its US ZIP and Canadian postal code tables. It never fills inship_city, and it can't look up destinations outside the US or Canada. Send both cities. - Weight and contents value. RocketShipIt sends
weightwithweight_unit(LBSorKGS, up to 150 lb / 70 kg), defaulting to 10.5 LBS. It also sends a contents value frommonetary_value, falling back toinsured_valueand then to 10.5, incurrency(default USD). UPS only uses the value on international lanes, where it is required. - Every request is one non-document package. RocketShipIt always sends
bill type
03(non-document) with one package, whatever you pass indocuments_onlyornum_of_packages. - Peak-season guarantees. When UPS suspends its service guarantees (for
example, in December), the raw response carries
guaranteeSuspended: true. RocketShipIt reportsis_guaranteedfor each service but doesn't surface this flag, so read it fromtransactions[].responseif your promise depends on the guarantee. - An empty list with no error can mean UPS couldn't resolve the address
and returned a candidate list instead. Check the raw response for
destinationPickListororiginPickList, then resend with the city and postal code from a candidate.
FedEx#
FedEx-REST calls FedEx's Retrieve Services and Transit Times API for FedEx
Ground, FedEx Express and SmartPost together. Each service returns a FedEx
service type (FEDEX_GROUND, PRIORITY_OVERNIGHT, SMART_POST and so on) as
service_code, a readable desc, the commit date, and delivery_days, which
is the upper end of FedEx's transit range. formatted_eta is a date only,
such as Fri January 16, with no time.
Only the postal codes and countries go to FedEx; weight is fixed at 10 lb and
isn't read from weight. For a quote that accounts for the real package,
take the transit time from a getallrates call instead: FedEx rates return
delivery_days and est_delivery_time for each service.
USPS#
USPS-REST calls the USPS Service Standards API with two ZIP codes and
nothing else, so it is domestic only. It returns every mail class USPS has
a standard for, including letters, flats and Media Mail, so filter the list to
the classes you actually ship. service_code is the USPS mail class
(PRIORITY_MAIL, USPS_GROUND_ADVANTAGE and so on), desc is the same name
in title case, and formatted_eta is the scheduled delivery date and time as
USPS writes it (2026-01-17T18:00:00). A mail class can appear more than once.
Two fields are only in the raw reply in transactions[].response:
delivery_daysisn't set. USPS's own count isserviceStandard("2", withserviceStandardMessage"2-Day").is_guaranteedis alwaysfalse, even for Priority Mail Express, which USPS does guarantee. Readdelivery.guaranteedDeliveryif you need it.
{
"carrier": "USPS-REST",
"action": "timeintransit",
"params": {
"key": "your-key-from-authenticate-request",
"ship_code": "59759",
"to_code": "90210"
}
}
DHL Express#
The DHL carrier uses DHL Express's capability check with your username
(site ID) and password. RocketShipIt marks the shipment dutiable when the
countries differ; send customs_value and currency for international
lanes. weight defaults to 5 LB. Each product comes back with DHL's local
product name and code and a delivery date and time. delivery_days isn't set.
{
"carrier": "DHL",
"action": "timeintransit",
"params": {
"username": "your-site-id",
"password": "your-password",
"ship_code": "90210",
"ship_country": "US",
"to_code": "M1B5K7",
"to_country": "CA",
"pickup_date": "2026-01-15",
"ready_time": "0900",
"customs_value": 250,
"currency": "USD"
}
}
Reading the response#
etais the carrier's local delivery time labelled as UTC. The carrier sends a wall-clock date and time with no zone, and RocketShipIt reads it as UTC. To display it, formatetain UTC (or useformatted_eta). Converting it to the destination's time zone shifts the delivery time by that zone's offset.- An unparseable date is not zero. If UPS, FedEx or DHL returns a service
without a date RocketShipIt can read,
etais-62135596800(year 1) andformatted_etareadsMon January 1. Treat anyetaat or below zero as unknown. - Business days, not calendar days.
delivery_daysfrom UPS and FedEx counts business days, so a two-day service shipped on Friday arrives on Tuesday. - Check
errorsbeforeservices. Carrier rejections, such as a bad postal code or a date outside the allowed window, come back inerrors. An emptyserviceslist with no errors is the UPS candidate-list case above.