Estimate Sales Order Shipping
POST/api/sales-orders/:salesOrder/shipping-estimates
Rates the sales order's product lines with the account's own EasyPost connection and records the run as an estimate. Parcels are built from product weights and dimensions (case packs first, then loose units), from each line's warehouse to the order's shipping address. Nothing on the order changes until a rate is applied.
orders:writeGrant this scope to your token under Settings → Developer → Personal Access Tokens.
Request body (all optional — send {} to rate the order as it stands):
origin_warehouse_id(integer, nullable): rate every item from this warehouse instead of each line's own warehouse.parcels(array, max 50, nullable): override the parcels built from product weights and dimensions. Each parcel:weight_oz(number, required, > 0, max 2400 = 150 lb),length_in/width_in/height_in(number, optional, > 0, max 108).refresh(boolean): bypass the 15-minute rate cache.
Response (data):
status:ok,not_connected(no EasyPost connection),key_rejected(the EasyPost API key was refused),missing_package_data(some products have no weight — listed inmissing_weight_products),no_origin_address(the shipping warehouse has no complete address),no_destination(no ship-to address),no_items(no product lines),no_rates(no carrier returned a rate) orrating_failed(EasyPost could not rate the shipment; try again). Onlyokcarriesoptions; every status comes back as 200 with a human-readablemessage.mode:productionortest— the mode of the EasyPost key that rated the shipment (test keys return list rates).currency: the order's currency; everyamountis converted to it.original_amount/original_currencyare what the carrier quoted.options[]: one per carrier service, cheapest first —key(<carrier>|<service>, pass it asoption_keywhen applying),carrier,service,carrier_account_id,amount,currency,original_amount,original_currency,delivery_days, andorigins[](the per-warehouse share when the order ships from several warehouses:warehouse_id,warehouse_name,amount,currency,parcels). A service is offered only when every origin warehouse can use it.warnings[]: notes such as products rated on a default weight or a missing exchange rate.missing_weight_products[]:{id, sku, name}of products with no weight.shipments[]: what was rated per origin warehouse —warehouse_id,warehouse_name,fromaddress,parcels[](weight_oz,length_in,width_in,height_in) andtotal_weight_oz.quoted_at,request_hash,estimate_id: when it was rated, a fingerprint of the rated request, and the recorded estimate's id (use it in the apply endpoint).defaults: the account's default markup (markup_typepercentorflat,markup_value) used when applying without an explicit markup.subject: the current Shipping lines that a rate would replace (existing_shipping_lines[]:id,description,quantity,amount,tax_rate), the currenttotal,currency, thenew_line_tax_ratea new Shipping line would carry andis_tax_included.
Identical requests within 15 minutes reuse the cached rates; send refresh: true to re-rate.
Only orders on the local channel or the B2B portal channel can be quoted. A channel order, or one that is cancelled, closed or invoiced, is refused with 422.
Authentication: Requires Bearer token.
Requires permission: sales_orders.update
Request
Responses
- 200
- 401
- 403
- 404
- 422
- 429
OK
Response Headers
Unauthenticated — the bearer token is missing, revoked, expired, or malformed. Never retry automatically; fix the credential. See the Errors guide.
Forbidden — the token lacks a required scope, the endpoint is not available to API tokens, or the user behind the token lacks the permission. A human must adjust the token scopes or user permissions; do not retry.
Not found — no record with the given identifier (or the route does not exist). Verify the ID before retrying.
Unprocessable Content
Response Headers
Rate limited — platform limit is 1,000 requests/min; individual tokens may carry lower limits. Honor the Retry-After header before retrying. See the Rate Limits guide.