# Calculate Shipping Costs

With the ShipStation API Rates endpoint, you can get shipping rates for multiple carrier and service options. You can then select the desired service for the shipment based on the response or display these at checkout to let your customers choose the fastest, cheapest, or most-trusted service.

If you are new to ShipStation API, make sure you have the following first:

- An active ShipStation API account. You can [sign up here](https://www.shipengine.com/signup/) if you haven't already.
- Your ShipStation [API key](/apis/shipengine/docs/guides/auth#api-keys) (a [sandbox API key](/apis/shipengine/docs/guides/auth#types-of-api-keys) will work for the steps provided below).
- A [tool to make an API call](/apis/shipengine/docs/getting-started/tools), like [curl](/apis/shipengine/docs/guides/curl) or [Postman](/apis/shipengine/docs/reference/postman).


There are multiple methods available for getting rates, each with their own use cases:

1. [Find rates with `shipment` details](#find-rates-using-shipment-details)
2. [Find rates with `shipment_id`](#find-rates-using-shipment-id)
3. [Find Rates with Package Types](#find-rates-with-package-types)
4. [Find Rates with Service Codes](#find-rates-with-service-codes)
5. [Find Rates with both Service Codes and Package Types](#find-rates-with-service-codes-and-package-types)


## Requirements

No matter which method you use, you’ll always need the `carrier_ids`, which will be included in the `rate_options` object. You can get rates for one or multiple carrier IDs. [List carriers](/apis/shipengine/docs/reference/list-carriers) to locate your carrier IDs.

There may also be additional requirements, depending on which method you use.

## About the /rates/ Endpoint

**POST /v1/rates/**

- Given some shipment details and rate options, this endpoint returns a list of rate quotes. You can then [Use a Rate to Print a Label](/apis/shipengine/docs/labels/create-from-rate).
- You can also choose to validate the address as part of the rate request to help ensure you receive the most-accurate rates possible. There are three address validation options:
  - `no_validation` - This is the default option and *does not* validate addresses nor does it confirm the accuracy of an address.
  - `validate_only` - Validates address accuracy *but* returns an error if the validation fails.
  - `validate_and_clean` - Validates address accuracy and updates the address with recommended adjustments.


## Find Rates Using Shipment Details

**Requirements:**

- `carrier_ids`
- `shipment` object


### Sample Request

In this example, the `shipment` details uses the `no_validation` value in the `validate_address` property.


```http
POST /v1/rates HTTP/1.1
Host: api.shipengine.com
API-Key: __YOUR_API_KEY_HERE__
Content-Type: application/json

{
  "rate_options": {
    "carrier_ids": [
      "se-123890"
    ]
  },
  "shipment": {
    "validate_address": "no_validation",
    "ship_to": {
      "name": "The President",
      "phone": "222-333-4444",
      "company_name": "",
      "address_line1": "1600 Pennsylvania Avenue NW",
      "city_locality": "Washington",
      "state_province": "DC",
      "postal_code": "20500",
      "country_code": "US",
      "address_residential_indicator": "no"
    },
    "ship_from": {
      "name": "ShipStation API Team",
      "phone": "222-333-4444",
      "company_name": "ShipStation API corp.",
      "address_line1": "4301 Bull Creek Road",
      "city_locality": "Austin",
      "state_province": "TX",
      "postal_code": "78731",
      "country_code": "US",
      "address_residential_indicator": "no"
    },
    "packages": [
      {
        "package_code": "package",
        "weight": {
          "value": 6,
          "unit": "ounce"
        }
      }
    ]
  }
}
```

## Find Rates Using Shipment ID

If you've already [created a shipment](/apis/shipengine/docs/shipping/create-a-shipment), then you can pass the `shipment_id` instead of the full shipment details.

**Requirements:**

- `carrier_ids`
- `shipment_id` for a previously created shipment.


### Sample Request


```http
POST /v1/rates HTTP/1.1
Host: api.shipengine.com
API-Key: __YOUR_API_KEY_HERE__
Content-Type: application/json

{
  "shipment_id": "se-123",
  "rate_options": {
    "carrier_ids": [
      "se-123890"
    ]
  }
}
```

> **IMPORTANT:**
You can pass *either* the full `shipment` details *or* a `shipment_id`, but you cannot pass both in the same request.


## Find Rates with Package Types

Use this method to filter the response by a specific set of package types. If no package type is specified, the *default* package type for that carrier is used, not all package types.

**Requirements:**

- `carrier_ids`
- `shipment_id` or `shipment` details
- `package_types` object and desired values


### Sample Request


```http
POST /v1/rates HTTP/1.1
Host: api.shipengine.com
API-Key: __YOUR_API_KEY_HERE__
Content-Type: application/json

{
  "shipment_id": "se-123",
  "rate_options": {
    "carrier_ids": [
      "se-123890"
    ],
    "service_codes": [],
    "package_types": [
      "flat_rate_envelope",
      "medium_flat_rate_box"
    ]
  }
}
```

## Find Rates with Service Codes

Use this method to filter the response by a specific set of service codes. If no service code is specified, *all* service codes are returned.

**Requirements:**

- `carrier_ids`
- `shipment_id` or `shipment` details
- `service_codes` object and desired values


### Sample Request


```http
POST /v1/rates HTTP/1.1
Host: api.shipengine.com
API-Key: __YOUR_API_KEY_HERE__
Content-Type: application/json

{
  "shipment_id": "se-123",
  "rate_options": {
    "carrier_ids": [
      "se-123890"
    ],
    "service_codes": [
      "usps_first_class_mail",
      "usps_priority_mail"
    ],
    "package_types": []
  }
}
```

## Find Rates with Service Codes and Package Types

Use this method to filter the resonse by a combination of service codes and package types.

**Requirements:**

- `carrier_ids`
- `shipment_id` or `shipment` details
- `package_types` object and desired values
- `service_codes` object and desired values


### Sample Request


```http
POST /v1/rates HTTP/1.1
Host: api.shipengine.com
API-Key: __YOUR_API_KEY_HERE__
Content-Type: application/json

{
  "shipment_id": "se-123",
  "rate_options": {
    "carrier_ids": [
      "se-123890"
    ],
    "service_codes": [
      "usps_first_class_mail",
      "usps_priority_mail",
      "ups_next_day_air_early_am"
    ],
    "package_types": [
      "flat_rate_envelope",
      "medium_flat_rate_box"
    ]
  }
}
```

## Overview of Custom Rate Shopper

You are not limited to `cheapest`, `fastest`, and `best_value` IDs. Custom configurations created in the ShipStation UI can be triggered via the API.

### Custom Rate Shopper Rules

In addition to the default strategies, you can trigger custom Rate Shopper rules created in your ShipStation account. To set up a custom rule, go to **Settings > Shipping > Rate Shopper** in the ShipStation UI. You can create rules from scratch or start from a recommended configuration.

Once created, use the rule's name or ID as the rate_shopper_id in the API request.

The following settings dictate how the custom rate shopper functions:

**Delivery Time Constraints**: Restricts eligible services to those with a carrier delivery estimate within a set number of days (calculated using only business days starting from the day after the ship date).

- If no estimate is provided by the carrier, the service is not eligible.


**Service Preferences**: Allows a preferred service to be used even if it isn't the cheapest, provided it is within a defined cost threshold of the cheapest service.

**AU/NZ Account Capabilities**: Allows for comparisons between Custom and Standard package types for accounts based in Australia and New Zealand.

### Example Request and Payload

This example shows how you pass the custom rule `rate_shopper_id`.


```http
POST /v1/labels/rate_shopper_id/{rate_shopper_id} HTTP/1.1
Host: api.shipstation.com
API-Key: __YOUR_API_KEY_HERE__
Content-Type: application/json

{
  "shipment": {
    "ship_to": {
      "name": "Amanda Miller",
      "phone": "555-555-5555",
      "address_line1": "525 S Winchester Blvd",
      "city_locality": "San Jose",
      "state_province": "CA",
      "postal_code": "95128",
      "country_code": "US",
      "address_residential_indicator": "yes"
    },
    "ship_from": {
      "name": "John Doe",
      "company_name": "Example Corp",
      "phone": "111-111-1111",
      "address_line1": "4009 Marathon Blvd",
      "city_locality": "Austin",
      "state_province": "TX",
      "postal_code": "78756",
      "country_code": "US"
    },
    "packages": [{
      "weight": {
        "value": 20,
        "unit": "ounce"
      },
      "dimensions": {
        "height": 6,
        "width": 12,
        "length": 24,
        "unit": "inch"
      }
    }]
  },
  "label_format": "pdf",
  "label_layout": "4x6"
}
```

### Best Practices and Troubleshooting

- **Rule Requirements**: Ensure the custom rule is published in the ShipStation UI.
- **Service Exclusion**: Do not include `carrier_id`, `service_code`, or `shipping_rule_id` inside the `shipment` object, or the API will return a 400-level validation error.
- **Error Responses**: If the custom rule cannot find a matching service based on the criteria (such as a Deliver-by Date restriction), the system returns a **404 - Rate Shopper could not find a matching service** error.
- **Preference Bounds**: This Service Preference relies on a "less than" calculation (e.g., if the rule is set for a maximum of $1.00 more, it applies to any rate that is $0.99 or less above the cheapest rate).


## About the Response

The response returns a list of rates from your connected carriers along with related shipment data. For domestic U.S. shipments, the first three rates typically include a `rate_attributes` object that highlights the best value, cheapest, and fastest options for quick comparison. The rates are then sorted from cheapest to most expensive.

When you make this call, a shipment object is automatically created with a `shipment_id`, allowing you to update it and retrieve new rates before purchasing a label.

To explore optional functionality, see the [advanced rating features guide.](/apis/shipengine/docs/rates/advanced-features)

### Rate Attributes

A single rate may have multiple attributes applied however each attribute only exists once in the response.
The following table defines the possible rate attributes and their meanings:

| Rate Attribute | Description |
|  --- | --- |
| `best_value` | Lowest cost option arriving on a specified date within 4 days, with free carrier coverage up to $100 and a free dropoff option. |
| `cheapest` | Lowest cost option |
| `fastest` | Fastest delivery option |


### Itemized Rate Breakdown

Each rate includes the itemized prices for:

| Property | Description |
|  --- | --- |
| `shipment_amount` | Cost of shipment only. |
| `insurance_amount` | Cost to insure shipment. |
| `confirmation_amount` | Cost to confirm shipment delivery. |
| `other_amount` | Fees and surcharges from the carrier. |


The **total rate** is the sum of all these amounts.

### Rate Details Object

You may want some additional details about the rates in the response. When it's available, we provide this additional information in the `rate_details` object.

Here is the structure:

| Property | Description |
|  --- | --- |
| `rate_detail_type` | Normalized type for the additional rate information. These types are enumerated as: `uncategorized`, `shipping`, `insurance`, `confirm`, `discount`, `fuel_charge`, `additional_fees`, `tariff`, `tax`, `delivery`, `handling`, `special_goods`, `pickup`, `location_fee`, `oversize`, `returns`, `notifications`, `tip`, `duties_and_taxes`, `brokerage_fee`, `admin_fee`, `adjustment` |
| `carrier_description` | Plain text description of the rate detail as provided by the carrier. |
| `carrier_billing_code` | Code for the billing type provided by the carrier. |
| `carrier_memo` | Additional text regarding this charge. Usually null. |
| `amount` | The `currency` and `amount` of the detailed charge |


The `rate_details` object should match the total of the `shipment_amount`, `insurance_amount`, `confirmation_amount`, and `other_amount` when it is provided.

> **TIP:**
### Don't want to wait for rates?
ShipStation API supports asynchronous requests using [webhooks](/apis/shipengine/docs/guides/webhooks). However, **we recommend waiting** if you need to display the rates as a 'next step' for your user, or if you're developing for a platform that does not support webhooks.


### Sample Response

The response can be lengthy depending on how many carriers you requested rates for. This sample response excludes all but one.


```json
{
    "rate_response": {
        "rates": [
            {
                "rate_id": "se-321654",
                "rate_type": "shipment",
                "carrier_id": "se-123890",
                "shipping_amount": {
                    "currency": "usd",
                    "amount": 10.1
                },
                "insurance_amount": {
                    "currency": "usd",
                    "amount": 0.0
                },
                "confirmation_amount": {
                    "currency": "usd",
                    "amount": 0.0
                },
                "other_amount": {
                    "currency": "usd",
                    "amount": 1.52
                },
                "rate_details": [
                    {
                        "rate_detail_type": "fuel_charge",
                        "carrier_description": "FedEx Ground Fuel",
                        "carrier_billing_code": null,
                        "carrier_memo": null,
                        "amount": {
                            "currency": "usd",
                            "amount": 1.52
                        },
                        "billing_source": "Carrier"
                    },
                    {
                        "rate_detail_type": "shipping",
                        "carrier_description": "Total Net Freight",
                        "carrier_billing_code": null,
                        "carrier_memo": null,
                        "amount": {
                            "currency": "usd",
                            "amount": 10.1
                        },
                        "billing_source": "Carrier"
                    }
                ],
                "zone": 6,
                "package_type": null,
                "delivery_days": 3,
                "guaranteed_service": false,
                "estimated_delivery_date": "2023-04-28T23:59:00Z",
                "carrier_delivery_days": "3",
                "ship_date": "2023-04-25T00:00:00Z",
                "negotiated_rate": false,
                "service_type": "FedEx Ground®",
                "service_code": "fedex_ground",
                "trackable": true,
                "carrier_code": "fedex",
                "carrier_nickname": "My FedEx account",
                "carrier_friendly_name": "FedEx",
                "validation_status": "has_warnings",
                "warning_messages": [
                    "FedEx may add a Home Delivery Surcharge to this shipment later if this is a residential address."
                ],
                "error_messages": [],
                "rate_attributes": [
                    "best_value",
                    "fastest",
                    "cheapest"
                ]
            }
        ]
        "invalid_rates": [],
        "rate_request_id": "se-987",
        "shipment_id": "se-12345",
        "created_at": "2023-04-25T22:44:33.8102925Z",
        "status": "completed",
        "errors": []
    },
    "shipment_id": "se-12345",
    "carrier_id": "se-123890",
    "service_code": null,
    "external_shipment_id": null,
    "shipment_number": null,
    "ship_date": "2023-04-25T00:00:00Z",
    "created_at": "2023-04-25T22:44:32.887Z",
    "modified_at": "2023-04-25T22:44:32.88Z",
    "shipment_status": "pending",
    "ship_to": {
        "instructions": null,
        "name": "The President",
        "phone": "222-333-4444",
        "company_name": "",
        "address_line1": "1600 Pennsylvania Avenue NW",
        "address_line2": null,
        "address_line3": null,
        "city_locality": "Washington",
        "state_province": "DC",
        "postal_code": "20500",
        "country_code": "US",
        "address_residential_indicator": "no"
    },
    "ship_from": {
        "instructions": null,
        "name": "ShipStation API Team",
        "phone": "222-333-4444",
        "company_name": "ShipStation API corp.",
        "address_line1": "4301 Bull Creek Road",
        "address_line2": null,
        "address_line3": null,
        "city_locality": "Austin",
        "state_province": "TX",
        "postal_code": "78731",
        "country_code": "US",
        "address_residential_indicator": "no"
    },
    "warehouse_id": null,
    "return_to": {
        "instructions": null,
        "name": "ShipStation API Team",
        "phone": "222-333-4444",
        "company_name": "ShipStation API corp.",
        "address_line1": "4301 Bull Creek Road",
        "address_line2": null,
        "address_line3": null,
        "city_locality": "Austin",
        "state_province": "TX",
        "postal_code": "78731",
        "country_code": "US",
        "address_residential_indicator": "no"
    },
    "is_return": false,
    "confirmation": "none",
    "customs": {
        "contents": "merchandise",
        "contents_explanation": null,
        "customs_items": [],
        "non_delivery": "return_to_sender",
        "buyer_shipping_amount_paid": null,
        "duties_paid": null,
        "terms_of_trade_code": null,
        "declaration": null,
        "invoice_additional_details": {
            "freight_charge": null,
            "insurance_charge": null,
            "other_charge": null,
            "discount": null
        },
        "importer_of_record": null
    },
    "external_order_id": null,
    "order_source_code": null,
    "advanced_options": {
        "bill_to_account": null,
        "bill_to_country_code": null,
        "bill_to_party": null,
        "bill_to_postal_code": null,
        "contains_alcohol": false,
        "delivered_duty_paid": false,
        "non_machinable": false,
        "saturday_delivery": false,
        "dry_ice": false,
        "dry_ice_weight": null,
        "fedex_freight": null,
        "third_party_consignee": false,
        "ancillary_endorsements_option": null,
        "freight_class": null,
        "custom_field1": null,
        "custom_field2": null,
        "custom_field3": null,
        "collect_on_delivery": null,
        "return_pickup_attempts": null,
        "additional_handling": false
    },
    "insurance_provider": "none",
    "tags": [],
    "packages": [
        {
            "shipment_package_id": "se-65432",
            "package_id": "se-3",
            "package_code": "package",
            "package_name": "Package",
            "weight": {
                "value": 6.00,
                "unit": "ounce"
            },
            "dimensions": {
                "unit": "inch",
                "length": 0.0,
                "width": 0.0,
                "height": 0.0
            },
            "insured_value": {
                "currency": "usd",
                "amount": 0.00
            },
            "label_messages": {
                "reference1": null,
                "reference2": null,
                "reference3": null
            },
            "external_package_id": null,
            "content_description": null,
            "products": []
        }
    ],
    "total_weight": {
        "value": 6.00,
        "unit": "ounce"
    },
    "items": []
}
```

## Automatic Label Creation with Rate Shopper

Once you understand how rate shopping works, you might want to automate the entire process. The **Rate Shopper** feature eliminates the need to manually review rates and select one — it automatically chooses and purchases a label based on your strategy in a single API call.

### How It Works

Instead of making two separate calls (one for rates, another for label creation), Rate Shopper:

1. Gets rates from all your wallet carriers
2. Selects the optimal rate based on your chosen strategy
3. Purchases the label automatically
4. Returns the completed label with details about which carrier and service were selected


### When to Use Rate Shopper

| Scenario | Recommended Approach |
|  --- | --- |
| **Automated fulfillment workflows** where you want consistent, hands-off carrier selection | ✅ Use Rate Shopper |
| **Displaying rates to customers** at checkout for them to choose | ❌ Use manual rate shopping (`POST /v1/rates`) |
| **Reviewing options** before committing to a carrier | ❌ Use manual rate shopping (`POST /v1/rates`) |
| **High-volume shipping** with clear cost or speed priorities | ✅ Use Rate Shopper |


### Available Strategies

The `rate_shopper_id` determines which carrier and service will be selected:

- **`cheapest`**: Best for non-urgent shipments where cost savings are the priority
- **`fastest`**: Best for time-sensitive shipments where speed matters most
- **`best_value`**: Best for balancing reasonable speed (within 4 days) without excessive cost


### Custom Rate Shoppers

In addition to standard strategies, you can pass a **service collection GUID** as the `rate_shopper_id` to use a custom rate shopper created from your account dashboard. Custom rate shoppers use a service collection to determine which carrier/service combinations are eligible, apply transit time filtering (with separate domestic/international thresholds), and select the cheapest qualifying rate. This feature requires an Advanced plan. Free plan can only use the default standard strategies (cheapest, fastest, best_value).

For details on creating and configuring custom rate shoppers, see [Rate Shopper - Automate Selecting the Lowest Rate](https://help.shipstation.com/hc/en-us/articles/4415714484123-Rate-Shopper-Automate-Selecting-the-Lowest-Rate).

> **Learn more**: See [Create a Label with Rate Shopper](/apis/shipengine/docs/labels/create-a-label#automated-carrier-selection-with-rate-shopper) for implementation details and examples.