# Get shipping rates

```http
POST https://secure.yoprint.com/v2/api/store/{team_slug}/v2/shipment_rate/goshippo
```

- API version: v2
- Operation ID: `v2_public_shipment_rate_goshippo`
- Section: Shipping › [Shipping rates and estimates](https://developer.yoprint.com/reference/shipping-rates-and-estimates.md)
- Web page: https://developer.yoprint.com/reference/shipping-rates-and-estimates/v2-shipment-rate-goshippo/
- Authentication: `Authorization: Bearer YOUR_API_KEY`

Asks Shippo for the rates to ship parcels between two addresses. Nothing is bought, and nothing is saved in YoPrint. Shippo keeps the request as a Shippo shipment in your Shippo account.

The reply is a trimmed copy of Shippo's shipment, without the usual `success`/`data` envelope, with HTTP 201. It has only these keys: `object_id`, `status`, `rates`, `messages`, `address_from`, `address_to`, `parcels`, `extra` (only `reference_1`, `billing`, `insurance`, `signature_confirmation`, `saturday_delivery`), `shipment_date` and `carrier_accounts`. The top-level `object_id` is the Shippo shipment, and each `rates[].object_id` is a rate you can buy with Buy a shipping label.

Options you want on the label (insurance, signature, Saturday delivery, third-party billing, references) go in `extra` here: the purchase can't change them.

Where the addresses come from. Rates are not tied to the YoPrint shipment: you send both addresses and the parcels yourself, YoPrint doesn't compare them with the shipment, and the label is bought for the rate's addresses and parcels. Build them the way the web app does. A shipment returns only ids (`customer_id`, `shipping_address_id`, `receiver_contact_id`, `customer_profile_id`), so read the records behind them:

- **Ship To** (`address_to`): Get a customer address, `GET /v1/api/store/{team_slug}/customer/{customer_id}/address/{shipping_address_id}`; and, when the shipment has one, the receiver contact with Get a contact by id, `GET /v1/api/store/{team_slug}/contact/{receiver_contact_id}`.
- **Ship From** (`address_from`): when `customer_profile_id` is set, the brand profile with Get a brand profile, `GET /v1/api/store/{team_slug}/customer/{customer_id}/profile/{customer_profile_id}` (its `address` is the Ship From address); otherwise one of your company locations (List company locations), with your team's `email` and `phone` from Get your company details.

| Shippo field | `address_to` | `address_from` |
| --- | --- | --- |
| `name` | receiver contact `first_name` + `last_name`; else the address `label`; else the customer's name | brand profile `company_name`; else the location `label` |
| `company` | the customer's name when it differs from `name`; empty when the shipment has a brand profile | empty |
| `street1` | address `address1` | address `address1` |
| `street2` | address `address2` | address `address2` |
| `city` | address `city` | address `city` |
| `state` | address `state_code` (or `state` when there is no code) | the same |
| `zip` | address `postcode` | address `postcode` |
| `country` | address `country_code` (or `country`) | the same |
| `email` | receiver contact `email` | brand profile `email`; else the team's `email` |
| `phone` | receiver contact `phone` | brand profile `phone`; else the team's `phone` |

Shippo needs `name`, `street1`, `city`, `state`, `zip` and `country` on both; company locations have no name or phone of their own.

Money here: a rate's `amount` is a decimal string in `currency` (`"12.40"`); parse it as a decimal. After purchase, each package's `charges` is that amount cut to 3 decimal places, in thousandths, an older encoding (`12400` is 12.40; usually a whole number of thousandths; a finer value comes back as a fractional number, or as an exact decimal string with `X-Yoprint-Decimal-Format: exact-v1`). On a multi-parcel label, every package repeats the rate's full amount: read the master package's value and don't add the packages up. See [Money and quantities](/concepts/money-and-quantities/).

The order of calls:

1. Optional: List Shippo carrier accounts, to limit rates to some of your accounts.
2. Get shipping rates with the addresses and parcels. Note the top-level `object_id` (the Shippo shipment) and the chosen rate's `object_id` (`rates[].object_id`).
3. Optional: Save a shipping estimate on the YoPrint shipment, to keep the quote.
4. Buy a shipping label with the rate's `object_id` as `rate_id`. This is the only step that costs money.
5. Print: Download labels as one PDF. Track: Get live tracking for a package.

## Permission

Any member of the team. No sales order permission is checked. Needs a connected, enabled Shippo integration (Settings > Integrations > Shippo Shipping). Without one the reply is 422 `goshippo_not_enabled` with no message.

## Business rules

- Both addresses need `name`, `street1`, `city`, `state`, `zip` and `country`.
- Each parcel needs its dimensions and weight (at least 0.01) and their units.
- Use `carrier_accounts` (plural). A singular `carrier_account` is read only when the plural is missing and is not checked.

## Side effects

- Calls Shippo, which stores a Shippo shipment in your Shippo account. Nothing is bought or saved in YoPrint.

## Path parameters

- `team_slug` (string, required): Your team slug, shown as Team ID next to your API key in Profile. Example `your-team`.

## Request body

Content type `application/json`, required.

Fields:

- `address_from` (object, required): Where the parcels ship from.
  - `city` (string, required): At most 255 characters.
  - `country` (string, required): ISO country code, for example `US`. Upper-cased for you. At most 50 characters.
  - `name` (string, required): At most 255 characters.
  - `state` (string, required): State or province code. Upper-cased for you. At most 50 characters.
  - `street1` (string, required): At most 255 characters.
  - `zip` (string, required): At most 20 characters.
  - `company` (string, optional): At most 255 characters.
  - `email` (string (email), optional): At most 255 characters.
  - `phone` (string, optional): At most 20 characters.
  - `street2` (string, optional): At most 255 characters.
  - `validate` (boolean, optional): Passed to Shippo: ask it to validate the address.
- `address_to` (object, required): Where they go. Same fields as `address_from` above.
- `parcels` (array of objects, required): One entry per box. More than one makes a multi-parcel shipment, bought as one rate. At least 1 item.
  - Each item:
    - `distance_unit` (string, required): One of: `"cm"`, `"in"`, `"ft"`, `"m"`, `"mm"`, `"yd"`.
    - `height` (number | string, required): Minimum 0.01.
    - `length` (number | string, required): A plain number, or a numeric string (the web app sends `"12"`). At least 0.01. Minimum 0.01.
    - `mass_unit` (string, required): One of: `"g"`, `"kg"`, `"lb"`, `"oz"`.
    - `weight` (number | string, required): A plain number or numeric string, in `mass_unit`. Minimum 0.01.
    - `width` (number | string, required): Minimum 0.01.
    - `extra` (object, optional)
      - `insurance` (object, optional): Insurance. `amount` and `currency` are required when you send it.
        - `amount` (number | string, optional): The insured value as a plain decimal in `currency` (`200` or `"200.00"` is 200.00), passed to Shippo unchanged: not thousandths and not a decimal pair. Minimum 0.
        - `content` (string, optional): At most 255 characters.
        - `currency` (string, optional): Exactly 3 characters.
        - `provider` (string, optional): One of: `"FEDEX"`, `"UPS"`, `"ONTRAC"`.
    - `template` (string, optional): A Shippo carrier parcel template token. The dimensions and weight are still required. At most 255 characters.
- `async` (boolean, optional): Leave false. With `true` Shippo answers before it has rates; the only later read is Save a shipping estimate with the reply's `object_id`, which reads the shipment back with its rates. Default `false`.
- `carrier_accounts` (array of strings, optional): Carrier account `object_id`s to rate. Omit to rate every active account.
- `extra` (object | null, optional): Label options, passed on to Shippo. Other Shippo `extra` keys are passed on unchecked.
  - `billing` (object, optional): Bill the shipment to another carrier account (third party or recipient). `account`, `country` and `type` are required when you send it.
    - `account` (string, optional): At most 255 characters.
    - `country` (string, optional): Exactly 2 characters.
    - `participation_code` (string, optional): At most 255 characters.
    - `type` (string, optional): At most 50 characters.
    - `zip` (string, optional): At most 20 characters.
  - `insurance` (object, optional): Insurance. `amount` and `currency` are required when you send it. Same fields as `parcels[].extra.insurance` above.
  - `reference_1` (string, optional): At most 255 characters.
  - `reference_2` (string, optional): At most 255 characters.
  - `saturday_delivery` (boolean, optional)
  - `signature_confirmation` (string, optional): One of: `"STANDARD"`, `"ADULT"`, `"CERTIFIED"`, `"INDIRECT"`, `"CARRIER_CONFIRMATION"`.
- `shipment_date` (string (date-time) | null, optional): When you plan to hand the parcels over. Defaults to now.

### Example request

```bash
curl -X POST 'https://secure.yoprint.com/v2/api/store/your-team/v2/shipment_rate/goshippo' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Accept: application/json' \
  -H 'X-Yoprint-Decimal-Format: exact-v1' \
  -H 'Content-Type: application/json' \
  -d '{
    "address_from": {
      "city": "Austin",
      "country": "US",
      "name": "Northwind Apparel",
      "phone": "+1 201 555 0123",
      "state": "TX",
      "street1": "100 Example Street",
      "zip": "78701"
    },
    "address_to": {
      "city": "Denver",
      "country": "US",
      "email": "alex@example.com",
      "name": "Alex Rivera",
      "state": "CO",
      "street1": "100 Example Street",
      "zip": "80202"
    },
    "extra": {
      "reference_1": "SO1001"
    },
    "parcels": [
      {
        "distance_unit": "in",
        "height": 4,
        "length": 12,
        "mass_unit": "lb",
        "weight": 2,
        "width": 10
      }
    ]
  }'
```

## Response

`201` A trimmed copy of the Shippo shipment with its rates, without the YoPrint envelope.

Fields:

- `object_id` (string, required): The Shippo shipment. Send it as `goshippo_shipment_id` to save an estimate.
- `rates` (array of objects, required)
  - Each item:
    - `amount` (string, optional)
    - `amount_local` (string, optional)
    - `arrives_by` (string | null, optional)
    - `attributes` (array of strings, optional): Shippo's tags, for example `CHEAPEST`.
    - `carrier_account` (string, optional)
    - `currency` (string, optional)
    - `currency_local` (string, optional)
    - `duration_terms` (string | null, optional)
    - `estimated_days` (integer | null, optional)
    - `included_insurance_price` (string | null, optional)
    - `messages` (array of objects, optional)
    - `object_created` (string, optional)
    - `object_id` (string, optional): The rate id. Send it as `rate_id` to buy this label.
    - `object_updated` (string, optional)
    - `provider` (string, optional)
    - `provider_image_200` (string, optional)
    - `provider_image_75` (string, optional): A URL of the carrier logo.
    - `servicelevel` (object, optional): Exactly these four keys; null when Shippo sends no service level.
      - `extended_token` (string, optional)
      - `name` (string, optional)
      - `terms` (string, optional)
      - `token` (string, optional)
    - `shipment` (string, optional): The Shippo shipment this rate belongs to.
- `address_from` (object, optional): Exactly `name`, `company`, `city`, `country`, `email`, `phone`, `state`, `street1`, `street2`, `zip`; empty strings for what Shippo leaves out.
- `address_to` (object, optional): The same ten keys as `address_from`.
- `carrier_accounts` (array of strings, optional)
- `extra` (object | null, optional)
- `messages` (array of objects, optional)
- `parcels` (array of objects, optional)
- `shipment_date` (string | null, optional)
- `status` (string, optional): Shippo's status. With `ERROR`, or no rates, read `messages`. One of: `"SUCCESS"`, `"QUEUED"`, `"ERROR"`.

Example response:

```json
{
  "address_from": {
    "city": "Austin",
    "company": "",
    "country": "US",
    "email": "",
    "name": "Northwind Apparel",
    "phone": "+1 201 555 0123",
    "state": "TX",
    "street1": "100 Example Street",
    "street2": "",
    "zip": "78701"
  },
  "address_to": {
    "city": "Denver",
    "company": "",
    "country": "US",
    "email": "alex@example.com",
    "name": "Alex Rivera",
    "phone": "",
    "state": "CO",
    "street1": "100 Example Street",
    "street2": "",
    "zip": "80202"
  },
  "carrier_accounts": [],
  "extra": {
    "reference_1": "SO1001"
  },
  "messages": [],
  "object_id": "shipment_0001",
  "parcels": [
    {
      "distance_unit": "in",
      "height": "4",
      "length": "12",
      "mass_unit": "lb",
      "weight": "2",
      "width": "10"
    }
  ],
  "rates": [
    {
      "amount": "12.40",
      "amount_local": "12.40",
      "arrives_by": null,
      "attributes": [
        "CHEAPEST"
      ],
      "carrier_account": "carrier_0001",
      "currency": "USD",
      "currency_local": "USD",
      "duration_terms": "Delivery in 2 to 5 days.",
      "estimated_days": 3,
      "included_insurance_price": null,
      "messages": [],
      "object_created": "2026-11-03T15:00:00Z",
      "object_id": "rate_0001",
      "object_updated": "2026-11-03T15:00:00Z",
      "provider": "USPS",
      "provider_image_200": "https://example.com/usps_200.png",
      "provider_image_75": "https://example.com/usps_75.png",
      "servicelevel": {
        "extended_token": "usps_ground_advantage",
        "name": "Ground Advantage",
        "terms": "",
        "token": "usps_ground_advantage"
      },
      "shipment": "shipment_0001"
    }
  ],
  "shipment_date": "2026-11-03T15:00:00Z",
  "status": "SUCCESS"
}
```

## Errors

- `401` The API key is missing or wrong (`unauthenticated`).
- `403` You are not allowed to do this. `api_access_not_in_plan`: your team's plan doesn't include API access (Pro and above, with an active subscription or trial), so every request answers this until the team upgrades. When your role lacks the permission the operation needs, the body is only `{"message": "Insufficient Permission"}`. Other refusals use the error envelope, with `unauthorized` or `user_is_not_authorized`.
- `404` Not found. `page_not_found`: the team slug is unknown, you are not a member of the team, or an id in the path is not one of this team's. `code: null`, with a message that starts "No query results for": there is no record with that id.
- `422` The request was refused and changed nothing. `validation_failed` lists what to fix in `error.fields`; other codes name a business rule, explained in `error.message`. A few checks answer with only `{"message": "..."}`. An operation that calls another service (a payment provider, a carrier, an accounting app) can answer `connect_timeout` ("Please retry again") when that service does not answer in time: the change may or may not have happened there, so read the record back before you retry.
  - When: A required address or parcel field is missing, a unit isn't in the list, or an `extra` option is out of range (`validation_failed`). Fix: Fix the fields listed in `error.fields`.
  - When: Shippo isn't connected or is disabled (`goshippo_not_enabled`). Fix: Connect Shippo in the web app first.
- `500` A business rule refused the request (see the operation's errors), or something failed inside YoPrint. Refusals use the error envelope with a code such as `action_not_allowed`; an unexpected failure answers `{"message": "Server Error"}`. Repeating a refusal gets the same answer; after an unexpected failure, read the record back before you retry a change.
  - When: Shippo refused the request or could not be reached. Shippo errors are not translated into 4xx replies. Fix: Check the addresses, parcels and ids, then retry once. Do not loop.

## Notes

- A 201 can still carry no rates: check `status`, `messages` and each rate's `messages`.
- Rates are quotes from Shippo. YoPrint doesn't record how long Shippo keeps a rate buyable: buy soon after rating, and if the purchase is refused, rate again.

## Related

- [List Shippo carrier accounts](https://developer.yoprint.com/reference/shipping-rates-and-estimates/v2-shipment-carrier-goshippo.md): `POST /v2/api/store/{team_slug}/v2/carrier_account/goshippo`
- [Save a shipping estimate](https://developer.yoprint.com/reference/shipping-rates-and-estimates/v2-shipment-estimate-create-goshippo.md): `POST /v2/api/store/{team_slug}/v2/shipment/{hash_id}/shipment_estimate/goshippo`
- [Buy a shipping label (charges your Shippo account)](https://developer.yoprint.com/reference/shipping-labels/v2-shipment-label-create-goshippo.md): `POST /v2/api/store/{team_slug}/v2/shipment/{hash_id}/label/goshippo`
- [Get a shipment](https://developer.yoprint.com/reference/shipments/v2-shipment-show.md): `GET /v2/api/store/{team_slug}/v2/shipment/{unique_key}`
- [Get a customer address](https://developer.yoprint.com/reference/customer-addresses/v1-customer-address-show.md): `GET /v1/api/store/{team_slug}/customer/{hash_id}/address/{id}`
- [Get a contact by id](https://developer.yoprint.com/reference/contacts/v1-contact-show.md): `GET /v1/api/store/{team_slug}/contact/{id}`
- [Get a brand profile](https://developer.yoprint.com/reference/customer-brand-profiles/v1-customer-profile-show.md): `GET /v1/api/store/{team_slug}/customer/{hash_id}/profile/{id}`
- [List company locations](https://developer.yoprint.com/reference/company-locations/v1-location-index.md): `GET /v1/api/store/{team_slug}/setting/location`
- [Get your company details](https://developer.yoprint.com/reference/company-settings/v1-setting-detail-show.md): `GET /v1/api/store/{team_slug}/setting/detail`
