ShipHub Get Rates
Version | Created By | Date | Notes |
---|---|---|---|
1.0 | Danail Deltchev | 06/17/2025 | First Publish |
The purpose of this page is to explain how to use and map the Get Rates function of our ShipHub integration
API Call: /getRates
Method: POST
Parameters: There are no specific header parameters everything is communicated through the body request. Authentication is with the Bearer token
Example:
{
"addresses":[
{
"address_1":"251 Little Falls Drive",
"zip":"19808",
"city":"Wilmington",
"residential":false,
"contact":{
"name":"Danail Deltchev",
"contact_name":"Threecolts LLC",
"email":"ddeltchev@threecolts.com",
"phone":"2126654322"
},
"country":"US",
"state":"DE",
"assignment":"from"
},
{
"address_1":"233 S Wacker Dr",
"zip":"60606",
"city":"Chicago",
"residential":false,
"contact":{
"name":"Charlie Smith",
"phone":"2126654322"
},
"country":"US",
"state":"IL",
"assignment":"to"
}
],
"options":{
"LengthUnit":{
"value":"IN"
},
"Package Type":{
"value":"Envelope"
},
"Print Receipt on Label":{
"value":0
},
"Signature":{
"value":"Adult Signature"
},
"WeightUnit":{
"value":"LB"
},
"isReturn":{
"value":false
},
"Saturday Delivery":{
"value":0
}
},
"packages":[
{
"quantity":1,
"weight":0.0,
"options":{
"Reference":{
"value":"ORDER-IL003"
}
}
}
]
}
Mapping (please note in the mapping there will be fields missing in the example):
Field | Mandatory | MCP Mapping | MCP Notes | |||
---|---|---|---|---|---|---|
addresses | Y | Please note it is mandatory to have 2 addresses always - from and to . From is the Warehouse address which we should pick from an MCP Location chosen in the Courier Shipping Providers section, where To is the destination, picked from the order. |
Both of these will be mapped together in the following Address fields |
| | address_1 | | | Y | from
: Location > Street1
to
: Orders > Shipping Street 1 | If Any field is longer than 35 characters we should break on the first space before the 35th character and move everything else to be concatenated with the relevant street2 field (with a space between the two values left). If the new value for address_2 is also longer than 35 characters we need to break again on the first space before the 35th character and move to address_3
If no spaces are found in a specific such field break on the 35th character exactly |
| | address_2 | | | N | from
: Location > Street2
to
: Orders > Shipping Street 2 | |
| | address_3 | | | N | * | As per the above note |
| | zip | | | Y | from
: Location > Post Code
to
: Orders > Shipping Postal Code | |
| | city | | | Y | from
: Location > City
to
: Orders > Shipping City | |
| | contact | | | Y | | |
| | | name | | N | from
: Location > Company Name OR Contact Name
to
: Orders > Shipping Buyer Name | For the “from” address “Company Name” is with priority if both are filled in |
| | | contact_name | | Y | from
: Location > Contact Name
to
: Orders > Shipping Buyer Name | |
| | | email | | Y | from
: Location > Email
to
: Orders > Buyer mail | |
| | | phone | | Y | from
: Location > Phone
to
: Orders > Shipping Phone | |
| | country | | | Y | from
: Location > Country 2 char code
to
: Orders > Shipping Country Code | In to
address if we don’t have the “Shipping Country Code” we have to obtain it by lookup with the “Shipping Country Name” |
| | state | | | N | from
: Location > State Province
to
: Orders > Shipping State Province | For both addresses we want to ensure we are sending a 2 letter Iso code of the state. If in address field we have 2 characters we have to check they are a valid state value. If we have a state name we have to map via lookup list and use the 2 char code. If not present don’t send |
| | assignment | | | Y | * | As mentioned we always have to send 2 address objects differentiating only by the “assignment” being to
and from
|
| options | | | | Y | | |
| | LengthUnit | | | | | |
| | | value | | Y | “IN” | Hardcoded |
| | Package Type | | | | | |
| | | value | | Y | “Customer Packaging” | Hardcoded |
| | Print Receipt on Label | | | | | |
| | | value | | N | Courier Shipping Providers > ShipHub Section > Print Receipt on Label | Yes or No (send 1 or 0)
IF there is no record set for this use: “0” as default | | | Signature | | | | | | | | | value | | N | Courier Shipping Providers > ShipHub Section > Signature | No Special Signature,
Adult Signature,
Direct Signature,
Indirect Signature #########
If first option is chosen don’t send Signature at all. For the rest pass the direct value selected. IF there is no record set for this don’t send this field as default | | | WeightUnit | | | | | | | | | value | | Y | "LB” | Hardcoded
We have to transform our weight from Grams to Pounds | | | isReturn | | | | | | | | | value | | Y | false | Hardcoded | | | Saturday Delivery | | | | | | | | | value | | N | Courier Shipping Providers > ShipHub Section > Saturday Delivery | Yes or No (send 1 or 0)
IF there is no record set for this send 0 as default | | packages | | | | | | | | | quantity | | | Y | “1” | Hardcoded | | | weight | | | Y | Products in Order > Weight | Multiplied by quantity of each product and summed between the products to get the final weight of the parcel
Note: weight should be converted accordingly not just summed | | | options | | | Y | | | | | | Reference | | | | | | | | | value | Y | Orders > ID + timestamp | Concatenate the two to achieve a unique reference every time we request a label for said order | | carrier | | | | N | Courier > Courier Shipping Provider > Courier ID | The concept of this is to allow for an integration to filter out carriers and get Rates only for specific carriers as opposed to call everything.
Trigger for this at the moment is Courier Shipping Providers
> Courier Filtration
. If set to get all
this is not necessary. If set to get per courier
we should call each courier in MCP that is setup for this integration with the respective Value provided in there.
Open to suggestions on structure to get to this information. |
On success we are to receive a payload with available shipping options. As previously described those need to be ordered by value cheapest to most expensive and the best value chosen for display or directly for label request
Please note: If “get per courier” is selected we should in theory call multiple times if we have multiple couriers set and then combine all responses before getting to the next step of display or rate choosing
Example Response:
{
"status": 200,
"data": {
"rates": [
{
"desc": "UPS Next Day Air Early",
"published_rate": "29.98",
"rate": "141.92",
"rate_detail": [
{
"type": "Transportation",
"amount": "111.94",
"published_rate": "0.00"
}
],
"currency": "USD",
"service_code": "14",
"est_delivery_time": "2025-06-18T08:00:00",
"package_type": "01",
"billing_weight": "",
"zone": "105",
"carrier": "UPS"
},
{
"desc": "UPS Next Day Air",
"published_rate": "17.17",
"rate": "45.17",
"rate_detail": [
{
"type": "Transportation",
"amount": "28.00",
"published_rate": "0.00"
}
],
"currency": "USD",
"service_code": "01",
"est_delivery_time": "2025-06-18T10:30:00",
"package_type": "01",
"billing_weight": "",
"zone": "105",
"carrier": "UPS"
},
{
"desc": "UPS Next Day Air Saver",
"published_rate": "17.06",
"rate": "44.36",
"rate_detail": [
{
"type": "Transportation",
"amount": "27.30",
"published_rate": "0.00"
}
],
"currency": "USD",
"service_code": "13",
"est_delivery_time": "2025-06-18T23:00:00",
"package_type": "01",
"billing_weight": "",
"zone": "135",
"carrier": "UPS"
},
{
"desc": "UPS Second Day Air AM",
"published_rate": "16.99",
"rate": "43.79",
"rate_detail": [
{
"type": "Transportation",
"amount": "26.80",
"published_rate": "0.00"
}
],
"currency": "USD",
"service_code": "59",
"est_delivery_time": "2025-06-19T10:30:00",
"package_type": "01",
"billing_weight": "",
"zone": "245",
"carrier": "UPS"
},
{
"desc": "UPS Second Day Air",
"published_rate": "16.84",
"rate": "42.64",
"rate_detail": [
{
"type": "Transportation",
"amount": "25.80",
"published_rate": "0.00"
}
],
"currency": "USD",
"service_code": "02",
"est_delivery_time": "2025-06-19T23:00:00",
"package_type": "01",
"billing_weight": "",
"zone": "205",
"carrier": "UPS"
}
],
"rate_errors": {
"FedEx": [
[
"Package weight is missing or invalid. PACKAGE_INDEX: 1"
]
],
"UPS": [
"You selected Fuel Surcharge, however UPS does not support it for UPS Next Day Air Early,UPS Next Day Air,UPS Next Day Air Saver,UPS Second Day Air AM,UPS Second Day Air shipments services. Please contact your sales representative or email testing+support@splgroup.com for additional assistance."
]
}
}
}
We evaluate by the rate
to order the received options. Wherever we display information we’d like to display for each received rate the following:
carrier
- desc
- rate
currency
- est_delivery_time
This will be part of the design as well but these are the fields we should utilise to show on every “Rate Card” we’ve received.
For storing information depending on the different steps - we need to create a record in Label Request
and have the following fields filled in:
- Courier - match the selected carrier when storing the label request by comparing the
carrier
value from the Rates with values stored inCourier
>Courier Shipping Provider
>Courier ID
. If there is a match we can select said courier. If there is no match we should store the value as received form the payload (or to be more precise as to be used or is used in the next step of Label creation) - Service - store the direct value from
desc
that we have selected to use for the label request - Label Count - to start always store 1
- Collection Date - always store the Day of the request
- Courier request id -
packages > options > Reference > value
from the payload we are sending - Rate - NEW FIELD - we should store the rate of the label as we receive the label back as this is the most accurate value for the final fee
Please note: The above Label Request store is as per the Eng team discretion and understanding when is best to store the label request. In a single GetRates request if there is a problem we will show it in the UI, and then comes the part with the label request at which point we will know what we are using for this label. Same goes to an extent for the Bulk request as well - it will get Rates - if error store on the order, then try to get a Label with the correct Service. Based on this it feels like the best time to store a Label request is either at the moment of receiving the response with the label or with the error so we can directly store everything on the Label Request itself
In case we’ve received an error or our internal validations fail we should capture error information and display in the label request prompt a message with said errors. In case a bulk request is being made I believe best thing to do is to store an Order Error with type Label so it can be tracked. More in the general handle of the UX re Shipping Labels
Example error response:
{
"status": 422,
"message": "The given data was invalid.",
"errors": {
"options.Package Type.value": [
"The options. package type.value field is required."
],
"addresses.0.address_1": [
"From 'Address Line 1' must be entered"
],
"addresses.0.city": [
"From Address 'City' must be entered"
],
"addresses.0.country": [
"From Address 'Country' must be entered"
],
"addresses.0.assignment": [
"The addresses.0.assignment field is required."
],
"addresses.1.address_1": [
"To 'Address Line 1' must be entered"
],
"addresses.1.city": [
"To Address 'City' must be entered"
],
"addresses.1.country": [
"To Address 'Country' must be entered"
],
"addresses.1.assignment": [
"The addresses.1.assignment field is required."
]
}
}
Error message is to be taken from the error response field “message” combined with field “errors” which is the detailed problems of the issue
PLEASE NOTE: as we are to call for all carriers always and then filter by carrier if we have such setup there is an option the call to return a successful response BUT the carrier we want to display is missing. We are to track this by the rate_errors
where we will receive errors from couriers that did not return any rates due to missing information. Each courier will be separate and will be based on the ID that should be set in our section of Coruers > Courier Shipping Provider > Courier ID