Shipments
Create Shipments
Creating a shipment is a two-step process. First, you will get shipping rates. Then you'll select one of those shipping rates to purchase.
Get RatesPOST `/v1/shipments`
There are three pieces of information we require to get rates: sender, recipient, and parcel. There are also some additional options you can pass in to configure the shipment.
Sender & Recipient
The sender and recipient information have the same properties, so we'll cover both here.
const sender = {
name: "Jamie Jones",
email: "jamie@packagex.io",
phone: "4844836699",
address: "500 7th ave, New York, NY, 10018",
};
We'll automatically parse the address for you. If you use an autocomplete like from Google Maps, Algolia, or PackageX, the format will come packed as a single string.
However, many autocomplete results don't come with a unit field, so typically that information is entered in a different input. If that is the case, you can provide a unit or apartment number in the address_line2
property.
const recipient = {
name: "Jamie Jones",
email: "jamie@packagex.io",
phone: "4844836699",
address: "500 7th ave, New York, NY, 10018",
address_line2: "Floor 10",
};
If you have the address information from the customer from multiple input fields, you can pass it through as an object
instead of an inline string
.
const sender = {
name: "Jamie Jones",
email: "jamie@packagex.io",
phone: "4844836699",
address: {
line1: "Jamie Jones",
line2: null, //If there is no unit number
city: "New York",
state: "NY",
postal_code: "10018",
},
};
Lastly, if you already have reference to an address that we parsed before, you can pass that address's ID property instead. This will speed up your request.
const sender = {
name: "Jamie Jones",
email: "jamie@packagex.io",
phone: "4844836699",
address: "addr_7407fb9ae37998dab83c505b3588a9c6ec3120822b07ac33d6c6b740f01b1000",
};
Parcel
For the parcel, you'll need to let us know the size and weight of the parcel. If you are using one of the
predefined packages, you can reference that using the type field or you can enter the length
, width
, and height
in inches. The weight
is entered in lbs.
const parcel = {
length: 5,
width: 1.4,
height: 10,
weight: 2,
};
You don't need to provide dimensions if using a predefined package. In fact, you don't strictly need to provide the weight either, but there are situations like with on-demand providers where not defaulting to the predefined package's max weight will result in better rates, so include this value if you have it.
const parcel = {
type: "usps_small_flat_rate_box",
weight: 2, //This is optional for predefined packages too
};
You can also optionally provide a special_handing
. The special_handling
field is currently experimental and will be standardized soon.
const parcel = {
type: "usps_small_flat_rate_box",
weight: 2,
special_handling: "TIME SENSITIVE", //experimental
};
If you want to let us know about specific inventory you are shipping, you can also pass an
Inventory array to describe the items that are inside of the parcel. This is done automatically for you if you are creating a shipment via a fulfillment_id
, but you can do so manually if you would like.
The reasons that you would want to include the inventory items in each parcel are:
const parcel = {
type: "usps_small_flat_rate_box",
weight: 2,
special_handling: "TIME SENSITIVE", //experimental
inventory: [
{
name: "Dispatch Roasters Tequila",
attributes: ["alcohol"],
},
{
name: "Dispatch Roasters Coffee",
vendor: "Dispatch, Inc",
origin_country: "Ethiopia",
},
],
};
- you are shipping something internationally and need to include customs information
- something you are shipping in this parcel needs additional care due to the item attributes like alcohol, hazardous materials, or pharmaceuticals.
- you want to include additional information for your records later
Options
Simple Options Example
const parcel = {
type: "usps_small_flat_rate_box",
weight: 2,
special_handling: "TIME SENSITIVE", //experimental
inventory: [
{
name: "Dispatch Roasters Tequila",
attributes: ["alcohol"],
},
{
name: "Dispatch Roasters Coffee",
vendor: "Dispatch, Inc",
origin_country: "Ethiopia",
},
],
};
const data = {
sender: {
name: "Jamie Jones",
email: "jamie@packagex.io",
phone: "4844836699",
address: "500 7th ave, New York, NY, 10018",
address_line2: "Floor 10",
},
recipient: {
name: "Ashley Yound",
email: "ashley@packagex.io",
phone: "4844836699",
address: "3 Brewster Rd, Newark, NJ, 07114",
},
parcels: [parcel],
options: {
verify_address: false,
provider_timeout: 5000,
},
};
const response = await fetch("https://api.packagex.io/v1/shipments", {
method: "POST",
headers: {
"PX-API-KEY": process.env.PX_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
const shipment = response.data;
Filter Results Example
In the example below, we're showing all of the filter properties that you can add. It's not advise to add all of those options because there can be conflicts with the filtering resulting in all of the rates being filtered out.
If all of the shipping rates get filtered out, then all of the rates will be returned besides those that are offline_delivery
to prevent accidentally leaking them to customers.
const data = {
sender: {
name: "Jamie Jones",
email: "jamie@packagex.io",
phone: "4844836699",
address: "500 7th ave, New York, NY, 10018",
address_line2: "Floor 10",
},
recipient: {
name: "Ashley Yound",
email: "ashley@packagex.io",
phone: "4844836699",
address: "3 Brewster Rd, Newark, NJ, 07114",
},
parcels: [
{
length: 5,
width: 1.4,
height: 10,
weight: 2,
item_description: "Candle",
special_handling: "TIME SENSITIVE",
},
],
options: {
verify_address: false,
provider_timeout: 5000,
request_provider_pickup: true,
providers: ["marketplace", "usps", "self"], //Add self to get your own private rates
service_levels: ["on_demand", "express"],
max_delivery_days: 1,
rate_types: ["provider_delivery", "in_person_pickup", "curbside_pickup", "locker_pickup", "offline_delivery"],
},
};
const response = await fetch("https://api.packagex.io/v1/shipments", {
method: "POST",
headers: {
"PX-API-KEY": process.env.PX_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
const shipment = response.data;
Multi-piece shipments
If shipping multiple boxes that are part of the same shipment, you can pass all of the parcels in an array. Each rate that is returned will have their price reflect both parcels.
Depending on the provider, someones both parcels will have the same tracking number while other times each parcel has a unique tracking number. This is dependent on how the provider does things. If the provider creates multiple tracking numbers, we'll add those tracking numbers to the tracking_number
property of the parcel and use a single tracking number for the shipment's tracking_number
property.
const data = {
sender: {
name: "Jamie Jones",
email: "jamie@packagex.io",
phone: "4844836699",
address: "500 7th ave, New York, NY, 10018",
address_line2: "Floor 10",
},
recipient: {
name: "Ashley Yound",
email: "ashley@packagex.io",
phone: "4844836699",
address: "3 Brewster Rd, Newark, NJ, 07114",
},
parcels: [
{
length: 5,
width: 1.4,
height: 10,
weight: 2,
item_description: "Candle",
special_handling: "TIME SENSITIVE",
},
],
options: {
verify_address: false,
provider_timeout: 5000,
request_provider_pickup: true,
providers: ["marketplace", "usps", "self"], //Add self to get your own private rates
service_levels: ["on_demand", "express"],
max_delivery_days: 1,
rate_types: ["provider_delivery", "in_person_pickup", "curbside_pickup", "locker_pickup", "offline_delivery"],
},
};
fetch("https://api.packagex.io/v1/shipments", {
method: "POST",
headers: {
"PX-API-KEY": process.env.PX_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
Refetch RatesPOST `/v1/shipments/:shipment/refresh`
After you already fetched rates, you can also fetch new rates. You'll want to do this if:
- Your rate has expired because the
rates_generated_at
is more than 15 minutes from now. - You want to update your options that you added into the shipment.
All of the options that are passed in for getting rates can also be passed in to refetch rates.
Purchase RatePOST `/v1/shipments/:shipment/purchase`
Properties
Now that you have generated your shipping rates, you are able to purchase the shipment. You'll want to find the id
of the shipping rate to purchase from the response that you received from generating the shipping rates.
Example
In this instance, we'll select the cheapest shipping rate from the response we received in the previous step. To purchase the shipment, we'll need the shipment ID from the response and the rate ID that we want to purchase. Everything else is optional.
const shipment = response.data; //the shipment is in the data property of the response object
const sorted_rate = shipment.rates.sort((a, b) => a.billed_amount - b.billed_amount);
const selected_rate = sorted[0];
const shipment_id = shipment.id;
const rate_id = selected_rate.id;
const body = {
rate_id: rate_id,
payment_reference: "Example",
label_size: "4x6",
};
const response = await fetch(`https://api.packagex.io/v1/shipments/${shipment.id}/purchase`, {
method: "POST",
headers: {
"PX-API-KEY": process.env.PX_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
const shipment = response.data;
Select Payment Method Example
In this instance, we'll select the cheapest shipping rate from the response we received in the previous step. To purchase the shipment, we'll need the shipment ID from the response and the rate ID that we want to purchase. Everything else is optional.
const payment_methods_response = await fetch(`https://api.packagex.io/v1/payment-methods`, {
method: "GET",
headers: {
"PX-API-KEY": process.env.PX_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}).then(res.json());
const payment_method_id = payment_methods_response.data[1].id; //Pick one that you want
const shipment = response.data; //the shipment is in the data property of the response object
const sorted_rate = shipment.rates.sort((a, b) => a.billed_amount - b.billed_amount);
const selected_rate = sorted[0];
const shipment_id = shipment.id;
const rate_id = selected_rate.id;
const body = {
rate_id: rate_id,
payment_method: payment_method_id,
};
fetch(`https://api.packagex.io/v1/shipments/${shipment.id}/purchase`, {
method: "POST",
headers: {
"PX-API-KEY": process.env.PX_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
Complete Example
const data = {
sender: {
name: "Jamie Jones",
email: "jamie@packagex.io",
phone: "4844836699",
address: "500 7th ave, New York, NY, 10018",
address_line2: "Floor 10",
},
recipient: {
name: "Ashley Yound",
email: "ashley@packagex.io",
phone: "4844836699",
address: "3 Brewster Rd, Newark, NJ, 07114",
},
parcels: [
{
length: 5,
width: 1.4,
height: 10,
weight: 2,
special_handling: "TIME SENSITIVE", //experimental
inventory: [
{
name: "Dispatch Roasters Tequila",
attributes: ["alcohol"],
},
{
name: "Dispatch Roasters Coffee",
vendor: "Dispatch, Inc",
origin_country: "Ethiopia",
},
],
},
],
options: {
verify_address: false,
provider_timeout: 5000,
max_delivery_days: 3, //Basically filter's out ground shipping
},
};
try {
let res = fetch("https://api.packagex.io/v1/shipments", {
method: "POST",
headers: {
"PX-API-KEY": process.env.PX_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
}).then((res) => res.json());
const shipment = res.data; //the shipment is in the data property of the response object
const sorted_rate = shipment.rates.sort((a, b) => a.billed_amount - b.billed_amount);
const selected_rate = sorted[0]; //Get the cheapest rate
const body = {
rate_id: selected_rate.id,
payment_reference: "Example",
label_size: "4x6",
};
res = await fetch(`https://api.packagex.io/v1/shipments/${shipment.id}/purchase`, {
method: "POST",
headers: {
"PX-API-KEY": process.env.PX_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}).then((res) => res.json());
const shipment = res.data;
const label_url = shipment.label_url;
} catch (err) {
console.error(err);
}