Rates
What a Rate is
A Rate is a pricing/service result returned for a Shipment in the current request and available Account/carrier context. It is not a booking, reservation, purchased service, permanent quote, standalone public CRUD resource, or persisted selection.
Get Rates
There are two public paths to Rate results:
- get Rates for an existing Shipment.
- Create an Order with Rates creates one Order and returns its Shipment Rates in the same response. It is one Order per request, not a batch operation.
Packed is not a prerequisite for either path.
Select a Rate for Label purchase
Shipment
-> Rate results
-> client selects rateId
-> Label purchase request
The client selects a returned rateId and supplies it to
the Label purchase request.
Retain that value only as needed for the current workflow. Selecting a Rate is
not documented as a mutation of Mailhub state.
See Labels for the bounded Label operation behavior. Use Select a Rate for the application-owned selection step.
Public Rate fields
A Get Rates call returns several Rates. Each one is a JSON object, and id is
the field that matters for the rest of the workflow: it is the value you keep
and send back when buying the Label. The other fields describe the option so
your application can choose between them.
A Rate is a returned decision result, not something you create. Your application decides which one to use: Mailhub does not mark one as recommended, fastest, or cheapest, and the order of the response is not a ranking.
The selected id travels in a nested rate object on the Label-purchase
request — there is no flat rate.id key:
{ "rate": { "id": "c4a1b2d3-..." } }
| Field | Classification | Public meaning |
|---|---|---|
id | IDENTIFIER | Returned Rate identifier. A selected returned id is supplied for the Label-purchase workflow. |
rate | PRICE | Returned Rate price value. |
currency | CURRENCY | Returned currency value associated with rate. |
carrier | CARRIER_DISPLAY | Returned carrier display value. |
serviceCode | SERVICE_CODE | Returned machine-facing carrier service code. |
serviceName | SERVICE_DISPLAY | Returned human-readable service name, for display. |
For the complete Rate response schema, including all optional fields and types, see the API Reference.
Public monetary amounts are JSON numbers, not strings — rate here, and
selectedRate.rate, selectedRate.retailRate and selectedRate.listRate on a
Label purchase. Read them as numbers and format them yourself for display: the
wire value carries the amount, not its presentation, so do not rely on a
trailing zero or on a fixed number of decimal places being present.
serviceCode is provider-dependent. Do not hard-code or parse it, and do not
build against a fixed list of values — the public contract does not define one.
Recognize a service by its returned serviceName, and carry the returned id
into the Label-purchase workflow.
Service code and service name
Each returned Rate carries two values that describe the same carrier service:
| Field | Role |
|---|---|
serviceCode | The carrier service code. Machine-facing. |
serviceName | The name of that service, human-readable and meant for display. |
A successful Label
purchase echoes the Rate it used back as selectedRate.
selectedRate.service carries that Rate's serviceCode value, not its
serviceName:
Rate
serviceCode ---------------> selectedRate.service
serviceName --- display only
selectedRate.service is returned metadata describing the Rate that was
purchased. It is not a request field: the Label purchase identifies the Rate by
rate.id alone. See Buy a Label.
Transit time and delivery dates
Four Rate fields describe timing, and they answer fewer distinct questions than their names suggest.
| Field | What it is |
|---|---|
deliveryDays | Carrier-supplied transit estimate, in days |
estDeliveryDays | The same estimate — always the same number as deliveryDays |
estimatedDeliveryDate | Date the carrier expects to deliver on, or null |
deliveryDateGuaranteed | Whether the carrier guarantees that date |
deliveryDays and estDeliveryDays always carry the same value. Every carrier
integration fills both from one quantity, so there is no committed-versus-estimated
distinction to read between them. Use either; do not compare them to each other, and do
not treat deliveryDays as a commitment. deliveryDateGuaranteed is the only field
that says whether anything is guaranteed.
0 means the carrier supplied no transit time for that Rate — it does not mean
same-day delivery. Some carriers return no transit figure at all, so 0 is a normal
value to receive.
The day basis is the carrier's own. One carrier reports business days in transit;
another derives a span from its own quoted delivery window. Mailhub passes the number
through without normalizing it, so the same integer from two carriers is not necessarily
comparable. Do not compute a delivery date from it — read estimatedDeliveryDate, which
is null when the carrier supplied none.
On a Label purchase, selectedRate.deliveryDate is this same estimatedDeliveryDate
value under a different name.
Result interpretation
More than one Rate result can be returned. The client makes the selection for its own workflow.
Do not infer cheapest, best, recommended, or otherwise ranked meaning from the response order unless a future public contract explicitly defines one.
Validity and outcomes
There is no Rate validity period, and no expiry timestamp. A Rate carries no TTL, the contract publishes none, and nothing in Mailhub rejects a Rate identifier for age. Do not build a countdown against a fixed number of minutes — no such number exists.
What does make a Rate identifier stop working is re-rating the same Shipment.
Requesting Rates for a Shipment replaces that Shipment's Rate set, so identifiers
returned by an earlier call for the same Shipment no longer resolve. The one exception
is a Rate a label purchase is already running against, which is retained until that
purchase settles. A purchase naming a Rate that is gone fails with 404 and the error
code Rate.NotFound.
Beyond that, the carrier is the authority at purchase time: Mailhub forwards the purchase, and a price the carrier will no longer honour is refused by the carrier, not by Mailhub. So: request Rates, and buy from that same set. If a purchase fails because the Rate is gone or the carrier declines it, request Rates again and buy from the new set rather than retrying the old identifier.
For V1, a successful response can contain rates: []. Inspect
carrierResponses when it is present in the response, together with the public
response envelope. This page does not assign a complete diagnostic meaning to
that field.
For Create an Order with Rates, the documented 422 response can represent an invalid
Order or a case where no carrier could rate the Shipment.
See Rate Errors for the documented error guidance.