Skip to content

Get shipping rates

Open .md

POST/v2/api/store/{team_slug}/v2/shipment_rate/goshippo

v2Operation ID v2_public_shipment_rate_goshippo

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.

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_slugstringrequired

    Your team slug, shown as Team ID next to your API key in Profile.

    • Example your-team

Request body

application/json, required.

  • address_fromobjectrequired

    Where the parcels ship from.

    Child fields (11)
    • citystringrequired
      • At most 255 characters
    • countrystringrequired

      ISO country code, for example US. Upper-cased for you.

      • At most 50 characters
    • namestringrequired
      • At most 255 characters
    • statestringrequired

      State or province code. Upper-cased for you.

      • At most 50 characters
    • street1stringrequired
      • At most 255 characters
    • zipstringrequired
      • At most 20 characters
    • companystring
      • At most 255 characters
    • emailstring (email)
      • At most 255 characters
    • phonestring
      • At most 20 characters
    • street2string
      • At most 255 characters
    • validateboolean

      Passed to Shippo: ask it to validate the address.

  • address_toobjectrequired

    Where they go.

  • parcelsarray of objectsrequired

    One entry per box. More than one makes a multi-parcel shipment, bought as one rate.

    • At least 1 item
    Fields of each item (8)
    • distance_unitstringrequired
      • One of: "cm", "in", "ft", "m", "mm", "yd"
    • heightnumber | stringrequired
      • Minimum 0.01
    • lengthnumber | stringrequired

      A plain number, or a numeric string (the web app sends "12"). At least 0.01.

      • Minimum 0.01
    • mass_unitstringrequired
      • One of: "g", "kg", "lb", "oz"
    • weightnumber | stringrequired

      A plain number or numeric string, in mass_unit.

      • Minimum 0.01
    • widthnumber | stringrequired
      • Minimum 0.01
    • extraobject
      Child fields (1)
      • insuranceobject

        Insurance. amount and currency are required when you send it.

        Child fields (4)
        • amountnumber | string

          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
        • contentstring
          • At most 255 characters
        • currencystring
          • Exactly 3 characters
        • providerstring
          • One of: "FEDEX", "UPS", "ONTRAC"
    • templatestring

      A Shippo carrier parcel template token. The dimensions and weight are still required.

      • At most 255 characters
  • asyncboolean

    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_accountsarray of strings

    Carrier account object_ids to rate. Omit to rate every active account.

  • extraobject | null

    Label options, passed on to Shippo. Other Shippo extra keys are passed on unchecked.

    Child fields (6)
  • shipment_datestring (date-time) | null

    When you plan to hand the parcels over. Defaults to now.

Response

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

Errors

  • 401The API key is missing or wrong (unauthenticated).

  • 403You 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.

  • 404Not 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.

  • 422The 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.
  • 500A 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.