Get Shipping Rates
/api/v1/shipments/{shipmentId}/rates
Open shipping rates in the API Reference.
Request Rates for a Shipment created by Create an Order. This call has no request body and no Order-status precondition — it works as soon as the Shipment exists, regardless of the Order's current status.
See Rates for the public Rate-result model and its bounded identifier handoff.
- cURL
- JavaScript
- C#
- Python
- Java
curl -s -X POST "${MAILHUB_API_BASE_URL}/api/v1/shipments/${SHIPMENT_ID}/rates" \
-H "Authorization: Bearer ${MAILHUB_ACCESS_TOKEN}"
const ratesResponse = await fetch(`${process.env.MAILHUB_API_BASE_URL}/api/v1/shipments/${shipmentId}/rates`, {
method: 'POST',
headers: {Authorization: `Bearer ${accessToken}`},
});
const {data: rateResults} = await ratesResponse.json();
const selectedRateId = rateResults.rates[0]?.id;
var ratesRequest = new HttpRequestMessage(HttpMethod.Post, $"/api/v1/shipments/{shipmentId}/rates");
ratesRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var ratesResponse = await client.SendAsync(ratesRequest);
using var ratesPayload = JsonDocument.Parse(await ratesResponse.Content.ReadAsStreamAsync());
var rates = ratesPayload.RootElement.GetProperty("data").GetProperty("rates");
var selectedRateId = rates[0].GetProperty("id").GetString();
import requests
rates_response = requests.post(
f"{api_base_url}/api/v1/shipments/{shipment_id}/rates",
headers={"Authorization": f"Bearer {access_token}"},
)
rate_results = rates_response.json()["data"]
selected_rate_id = rate_results["rates"][0]["id"] if rate_results["rates"] else None
// Java 11+ java.net.http — no MailHub package to install and no third-party client.
var request = HttpRequest.newBuilder()
.uri(URI.create(apiBaseUrl + "/api/v1/shipments/" + shipmentId + "/rates"))
.header("Authorization", "Bearer " + accessToken)
.POST(HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
// Parse response.body() with your own JSON library. Keep the id of the Rate your
// application chooses from data.rates, and check data.carrierResponses for the
// carriers that failed while others succeeded.
Response
{
"success": true,
"data": {
"totalCount": 2,
"carrierCount": 2,
"rates": [
{
"id": "c4a1b2d3-...",
"carrier": "USPS",
"serviceCode": "<carrier-specific service code>",
"serviceName": "USPS Priority Mail",
"rate": 8.42,
"currency": "USD",
"deliveryDays": 2,
"estDeliveryDays": 2,
"deliveryDateGuaranteed": false
},
{
"id": "d5b2c3e4-...",
"carrier": "UPS",
"serviceCode": "<carrier-specific service code>",
"serviceName": "UPS Ground",
"rate": 11.15,
"currency": "USD",
"deliveryDays": 4,
"estDeliveryDays": 4,
"deliveryDateGuaranteed": false
}
],
"carrierResponses": [
{"carrier": "USPS", "success": true, "errorCode": null, "errorMessage": null},
{"carrier": "UPS", "success": true, "errorCode": null, "errorMessage": null}
]
},
"errors": null
}
carrier, serviceCode, and serviceName above are illustrative example
values, not a fixed enum — exact carriers/services depend on your account,
sub-account, and environment configuration. serviceCode is carrier-specific
and its shape is not part of the public contract: pass it through, and do not
parse, hard-code, or switch on it. Select a service by matching serviceName
where you need to, and keep the returned Rate id for the purchase. listRate, retailRate,
billingType, mailClass, zone, and estimatedDeliveryDate are also
present on each rate when the carrier returns them; see the
API Reference for the complete field list.
Continue with Select a Rate before Buy a Label. Working with USPS? See USPS with Mailhub. Rate quotes are not guaranteed to remain valid indefinitely — no specific expiry/TTL is part of the current public contract, so request fresh rates if a meaningful amount of time has passed before purchasing.
Errors
404 if the Shipment does not exist for your account. See
Rate Errors for general recovery guidance.