Documentation
Everything you need to integrate the rateship SDK into your Node backend.
Everything you need to integrate the rateship SDK into your Node backend.
client.getRates(request) calls every configured provider in parallel and returns a single normalized list. Failures are collected in errors[] rather than thrown, so one bad provider never blocks the call.
const { rates, errors } = await client.getRates({
from: {
name: "Warehouse",
street1: "500 Terry A Francois Blvd",
city: "San Francisco",
state: "CA",
zip: "94158",
country: "US",
},
to: {
name: "Jane Doe",
street1: "1600 Amphitheatre Pkwy",
city: "Mountain View",
state: "CA",
zip: "94043",
country: "US",
},
parcel: {
weight: 2,
weight_unit: "lb",
length: 10,
width: 8,
height: 6,
distance_unit: "in",
},
});
rates.forEach((r) => {
console.log(r.provider, r.carrier, r.service, r.price_cents);
});interface RateRequest {
from: Address;
to: Address;
parcel: Parcel; // single parcel at v2.0 (multi-parcel is v2.1+)
}
interface Address {
name: string;
street1: string;
street2?: string;
city: string;
state: string;
zip: string;
country: "US"; // v2.0 locked to US; widens to ISO 3166-1 in v2.1+
phone?: string; // adapters throw VALIDATION_ERROR when a carrier needs it
email?: string;
}
interface Parcel {
weight: number;
weight_unit: "lb" | "oz";
length: number;
width: number;
height: number;
distance_unit: "in";
}Rates are sorted ascending by price_cents regardless of provider. errors[] is empty when every provider succeeded.
interface RatesResponse {
rates: NormalizedRate[]; // sorted by price_cents ascending
errors: ProviderError[]; // empty when all providers succeeded
}
interface NormalizedRate {
provider: "easypost" | "shippo" | "shipengine";
carrier: string; // "UPS", "USPS", "FedEx"
service: string; // "Ground", "Priority Mail", etc.
price_cents: number; // integer cents, always USD at v2.0
currency: "USD";
estimated_days: number | null;
estimated_delivery: string | null; // ISO date
rate_id: string; // provider-native rate id
raw: object; // full provider response, untouched
}
interface ProviderError {
provider: "easypost" | "shippo" | "shipengine";
code: ErrorCode; // AUTH_FAILED, TIMEOUT, PROVIDER_ERROR, ...
message: string;
}The SDK uses Promise.allSettled, not Promise.all. If EasyPost succeeds and Shippo times out, you get 19 rates plus one timeout error, not an exception that throws away the EasyPost work.
const { rates, errors } = await client.getRates(request);
if (rates.length === 0 && errors.length > 0) {
// Every provider failed. Inspect the error codes to decide what to do.
console.error("All providers failed:", errors);
return;
}
if (errors.length > 0) {
// Partial failure, log but continue with what we have.
console.warn("Some providers failed:", errors);
}
const cheapest = rates[0];RateShipError with code VALIDATION_ERROR before fan-out.CONFIGURATION_ERROR at construction.Next: Buying Labels.
client.getRates(request) calls every configured provider in parallel and returns a single normalized list. Failures are collected in errors[] rather than thrown, so one bad provider never blocks the call.
const { rates, errors } = await client.getRates({
from: {
name: "Warehouse",
street1: "500 Terry A Francois Blvd",
city: "San Francisco",
state: "CA",
zip: "94158",
country: "US",
},
to: {
name: "Jane Doe",
street1: "1600 Amphitheatre Pkwy",
city: "Mountain View",
state: "CA",
zip: "94043",
country: "US",
},
parcel: {
weight: 2,
weight_unit: "lb",
length: 10,
width: 8,
height: 6,
distance_unit: "in",
},
});
rates.forEach((r) => {
console.log(r.provider, r.carrier, r.service, r.price_cents);
});interface RateRequest {
from: Address;
to: Address;
parcel: Parcel; // single parcel at v2.0 (multi-parcel is v2.1+)
}
interface Address {
name: string;
street1: string;
street2?: string;
city: string;
state: string;
zip: string;
country: "US"; // v2.0 locked to US; widens to ISO 3166-1 in v2.1+
phone?: string; // adapters throw VALIDATION_ERROR when a carrier needs it
email?: string;
}
interface Parcel {
weight: number;
weight_unit: "lb" | "oz";
length: number;
width: number;
height: number;
distance_unit: "in";
}Rates are sorted ascending by price_cents regardless of provider. errors[] is empty when every provider succeeded.
interface RatesResponse {
rates: NormalizedRate[]; // sorted by price_cents ascending
errors: ProviderError[]; // empty when all providers succeeded
}
interface NormalizedRate {
provider: "easypost" | "shippo" | "shipengine";
carrier: string; // "UPS", "USPS", "FedEx"
service: string; // "Ground", "Priority Mail", etc.
price_cents: number; // integer cents, always USD at v2.0
currency: "USD";
estimated_days: number | null;
estimated_delivery: string | null; // ISO date
rate_id: string; // provider-native rate id
raw: object; // full provider response, untouched
}
interface ProviderError {
provider: "easypost" | "shippo" | "shipengine";
code: ErrorCode; // AUTH_FAILED, TIMEOUT, PROVIDER_ERROR, ...
message: string;
}The SDK uses Promise.allSettled, not Promise.all. If EasyPost succeeds and Shippo times out, you get 19 rates plus one timeout error, not an exception that throws away the EasyPost work.
const { rates, errors } = await client.getRates(request);
if (rates.length === 0 && errors.length > 0) {
// Every provider failed. Inspect the error codes to decide what to do.
console.error("All providers failed:", errors);
return;
}
if (errors.length > 0) {
// Partial failure, log but continue with what we have.
console.warn("Some providers failed:", errors);
}
const cheapest = rates[0];RateShipError with code VALIDATION_ERROR before fan-out.CONFIGURATION_ERROR at construction.Next: Buying Labels.