# Rate Shopping With the 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. There are multiple methods available for getting rates, each with their own use cases: - [Find rates with `shipment` details](#example-find-rates-with-shipment-details) - [Find rates with `shipment_id`](#example-find-rates-with-shipment-id) - [Find Rates with Package Types](#example-find-rates-with-package-types) - [Find Rates with Service Codes](#example-find-rates-with-service-codes) - [Find Rates with both Service Codes and Package Types](#example-find-rates-with-service-codes--package-types) Additionally, you can [get rate estimates](#rate-estimates) with a subset of the information required to create a label. ## 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](/list-carriers) to locate your carrier IDs. There may also be additional requirements, depending on which method you use. ## About the /rates/ Endpoint **POST /v2/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](/create-labels#create-label-from-a-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. ## Example: Find Rates with Shipment Details **Requirements:** - `carrier_ids` - `shipment` object ### Sample Request In this example, the `shipment` details has the `no_validation` value in the `validate_address` property. ```http POST /v2/rates HTTP/1.1 Host: api.shipstation.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 Team", "phone": "222-333-4444", "company_name": "ShipStation", "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" } } ] } } ``` ## Example: Find Rates with Shipment ID If you've already [created a shipment](/list-shipments), 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 /v2/rates HTTP/1.1 Host: api.shipstation.com API-Key: __YOUR_API_KEY_HERE__ Content-Type: application/json { "shipment_id": "se-123", "rate_options": { "carrier_ids": [ "se-123890" ] } } ``` You can pass *either* the full `shipment` details *or* a `shipment_id`, but you cannot pass both in the same request. ## Example: 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 /v2/rates HTTP/1.1 Host: api.shipstation.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" ] } } ``` ## Example: 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 /v2/rates HTTP/1.1 Host: api.shipstation.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": [] } } ``` ## Example: Find Rates with Service Codes & Package Types Use this method to filter the response 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 /v2/rates HTTP/1.1 Host: api.shipstation.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" ] } } ``` ## About the Response 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. 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. Don't want to wait for rates? We support asynchronous requests using 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": [] } ] "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 Team", "phone": "222-333-4444", "company_name": "ShipStation", "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 Team", "phone": "222-333-4444", "company_name": "ShipStation", "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": [] } ``` ## Rate Estimates You may find it useful to quickly estimate a rate so you can, for example, add shipping charges to your customer's shopping cart. Estimates work by providing a subset of the information required to create a label using the `/v2/rates/estimate` endpoint. You can use this method to allow customers to quickly compare rates across services, carriers, and more without having to fill in all the information required to create a label. Limitations of Rate Estimates This endpoint does not support multi-package shipments or filtering using the `rate_options` property. You can filter by carrier adding the desired carrier IDs to the `carrier_ids` array. When requesting an estimate, we recommend including the following for the best results: - Postal Code To - Postal Code From - Weight - Dimensions (optional, but recommended) ### Sample Request **POST /v2/rates/estimate** ```http POST /v2/rates/estimate HTTP/1.1 Host: api.shipstation.com API-Key: __YOUR_API_KEY_HERE__ Content-Type: application/json { "carrier_ids": [ "se-123890" ], "from_country_code": "US", "from_postal_code": "78756", "to_country_code": "US", "to_postal_code": "95128", "to_city_locality": "San Jose", "to_state_province": "CA", "weight": { "value": 1.0, "unit": "ounce" }, "dimensions": { "unit": "inch", "length": 5.0, "width": 5.0, "height": 5.0 }, "confirmation": "none", "address_residential_indicator": "no" } ``` Only an Estimate! Rate estimates are not exact quotes. They do not include things like `insurance_amount` and may not include other items such as fuel surcharges, customs charges, or other carrier fees. ## Automatic Label Creation with Rate Shopper The Rate Shopper feature takes rate shopping to the next level by automatically selecting and purchasing a label based on your chosen strategy. Instead of manually reviewing rates and selecting one, the Rate Shopper does this for you in a single API call. ### How Rate Shopper Works 1. You provide complete shipment details (addresses, packages, etc.) 2. You specify a strategy: `cheapest`, `fastest`, or `best_value` 3. Rate Shopper gets rates from all eligible carriers 4. Rate Shopper selects the optimal rate based on your strategy 5. A label is automatically created and returned ### Available Strategies | Strategy | Description | Use Case | | --- | --- | --- | | `cheapest` | Lowest cost option | Best for non-urgent shipments where cost savings are the priority | | `fastest` | Fastest option at the lowest price | Best for time-sensitive shipments where speed matters most | | `best_value` | Lowest cost option arriving within 4 days | Best for shipments where you want reasonable speed without excessive cost | ### Requirements - Wallet carriers connected to your ShipStation API account - Complete shipment details (do not include `carrier_id`, `service_code`, or `shipping_rule_id`) - Valid `rate_shopper_id` (cheapest, fastest, or best_value) ### Example: Create Label with Rate Shopper **POST /v2/labels/rate_shopper_id/{rate_shopper_id}** This example uses the `cheapest` strategy to automatically select the lowest-cost carrier and service. ```http POST /v2/labels/rate_shopper_id/cheapest 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" } ``` ### Sample Response The response includes the created label plus information about which rate was selected: ```json { "label_id": "se-396884371", "status": "completed", "shipment_id": "se-1080108982", "ship_date": "2026-02-27T08:00:00Z", "created_at": "2026-02-27T17:37:21.648Z", "shipment_cost": { "currency": "usd", "amount": 17.58 }, "tracking_number": "1ZYF85760394283643", "carrier_id": "se-5904054", "service_code": "ups_ground", "carrier_code": "ups", "rate_shopper_id": "cheapest", "label_download": { "pdf": "https://api.shipstation.com/v2/downloads/10/xxx/label-396884371.pdf", "png": "https://api.shipstation.com/v2/downloads/10/xxx/label-396884371.png", "zpl": "https://api.shipstation.com/v2/downloads/10/xxx/label-396884371.zpl", "href": "https://api.shipstation.com/v2/downloads/10/xxx/label-396884371.pdf" } } ``` Rate Shopper vs Manual Rate Shopping Use Rate Shopper when you want to automate carrier selection in production workflows. Use manual rate shopping (POST /v2/rates) when you need to display rates to customers or review options before purchasing. **Important**: Do not include `carrier_id`, `service_code`, or `shipping_rule_id` in your shipment object when using Rate Shopper. The API will return an error if these fields are present, as Rate Shopper automatically determines these values. ### Troubleshooting Rate Shopper **No rates available error** If you receive a 404 error, check: - You have wallet carriers connected - Your shipment parameters are valid - The destination is supported by your carriers - Package dimensions and weight are within carrier limits If you need specific carrier selection, use the standard label creation endpoint with explicit `carrier_id` and `service_code`.