Documentation Index
Fetch the complete documentation index at: https://mintlify.com/openshiporg/openfront/llms.txt
Use this file to discover all available pages before exploring further.
Openfront’s shipping system provides a flexible adapter-based architecture for integrating with shipping carriers. Built-in support includes Shippo, ShipEngine, and manual shipping, with the ability to add custom providers.
Shipping Provider Architecture
Each shipping provider implements a standard set of functions:
getRatesFunction - Get real-time shipping rates
createLabelFunction - Generate shipping labels
cancelLabelFunction - Cancel/refund labels
validateAddressFunction - Validate shipping addresses
trackShipmentFunction - Track shipment status
Shipping Providers
Shippo Integration
Shippo provides access to multiple carriers through a single API with competitive rates.
Configuration
SHIPPO_API_TOKEN=shippo_...
Getting Shipping Rates
The Shippo adapter calculates rates from multiple carriers:
export async function getRatesFunction({ provider, order, dimensions }) {
if (!dimensions) {
throw new Error("Dimensions are required to get shipping rates");
}
// Create address first
const addressToResponse = await fetch(`${SHIPPO_API_URL}/addresses/`, {
method: "POST",
headers: {
Authorization: `ShippoToken ${provider.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: `${order.shippingAddress.firstName} ${order.shippingAddress.lastName}`,
street1: order.shippingAddress.address1,
city: order.shippingAddress.city,
state: order.shippingAddress.province,
zip: order.shippingAddress.postalCode,
country: order.shippingAddress.country.iso2,
phone: order.shippingAddress.phone,
}),
});
const addressTo = await addressToResponse.json();
// Create shipment to get rates
const shipmentResponse = await fetch(`${SHIPPO_API_URL}/shipments/`, {
method: "POST",
headers: {
Authorization: `ShippoToken ${provider.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
address_from: { /* warehouse address */ },
address_to: addressTo.object_id,
parcels: [{
length: dimensions.length,
width: dimensions.width,
height: dimensions.height,
distance_unit: dimensions.unit,
weight: dimensions.weight,
mass_unit: dimensions.weightUnit,
}],
}),
});
const shipment = await shipmentResponse.json();
return shipment.rates.map((rate) => ({
id: rate.object_id,
providerId: provider.id,
service: rate.servicelevel.name,
carrier: rate.provider,
price: rate.amount,
currency: rate.currency,
estimatedDays: rate.estimated_days,
}));
}
Creating Shipping Labels
Generate shipping labels with tracking:
export async function createLabelFunction({
provider,
order,
rateId,
dimensions,
}) {
// Create transaction (label) with the specific rate
const transactionResponse = await fetch(`${SHIPPO_API_URL}/transactions/`, {
method: "POST",
headers: {
Authorization: `ShippoToken ${provider.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
rate: rateId,
label_file_type: "PDF",
async: false,
}),
});
const transaction = await transactionResponse.json();
return {
status: "purchased",
data: transaction,
carrier: transaction.provider,
service: transaction.servicelevel?.name,
trackingNumber: transaction.tracking_number,
trackingUrl: transaction.tracking_url_provider,
labelUrl: transaction.label_url,
};
}
Address Validation
export async function validateAddressFunction({ provider, address }) {
const response = await fetch(`${SHIPPO_API_URL}/addresses/`, {
method: "POST",
headers: {
Authorization: `ShippoToken ${provider.accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: `${address.firstName} ${address.lastName}`,
street1: address.address1,
city: address.city,
state: address.province,
zip: address.postalCode,
country: address.country.iso2,
validate: true,
}),
});
const validation = await response.json();
return {
isValid: validation.validation_results.is_valid,
suggestedAddress: validation.validation_results.is_valid ? {
address1: validation.street1,
city: validation.city,
province: validation.state,
postalCode: validation.zip,
} : null,
errors: validation.validation_results.messages || [],
};
}
ShipEngine Integration
ShipEngine provides enterprise-grade shipping with support for major carriers.
Configuration
Unit Conversion
ShipEngine requires specific unit formats:
const WEIGHT_UNIT_MAP = {
oz: "ounce",
lb: "pound",
kg: "kilogram",
g: "gram",
};
const DIMENSION_UNIT_MAP = {
in: "inch",
cm: "centimeter",
};
function convertDimensions(dim) {
if (dim.unit === "m") {
return {
length: dim.length * 100,
width: dim.width * 100,
height: dim.height * 100,
unit: "centimeter",
};
} else if (dim.unit === "ft") {
return {
length: dim.length * 12,
width: dim.width * 12,
height: dim.height * 12,
unit: "inch",
};
}
return {
length: dim.length,
width: dim.width,
height: dim.height,
unit: DIMENSION_UNIT_MAP[dim.unit] || dim.unit,
};
}
Getting Rates
export async function getRatesFunction({ provider, order, dimensions }) {
// List available carriers
const carriers = await listCarriersFunction(provider);
const carrier_ids = carriers.map((carrier) => carrier.carrier_id);
const convertedDimensions = convertDimensions(dimensions);
const convertedWeight = convertWeight(dimensions);
const payload = {
shipment: {
ship_to: { /* destination address */ },
ship_from: { /* warehouse address */ },
packages: [{
weight: convertedWeight,
dimensions: convertedDimensions,
}],
},
rate_options: { carrier_ids },
};
const response = await fetch(`${SHIPENGINE_API_URL}/rates`, {
method: "POST",
headers: {
"API-Key": provider.accessToken,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const result = await response.json();
return result.rate_response.rates.map((rate) => ({
id: JSON.stringify({
id: rate.rate_id,
service: rate.service_code,
}),
providerId: provider.id,
service: rate.service_type || rate.service_code,
carrier: rate.carrier_friendly_name,
price: (rate.shipping_amount.amount + rate.other_amount.amount).toFixed(2),
currency: rate.shipping_amount.currency.toUpperCase(),
estimatedDays: rate.delivery_days,
}));
}
Creating Labels
export async function createLabelFunction({
provider,
order,
rateId,
dimensions,
}) {
const { service, id } = JSON.parse(rateId);
const payload = {
shipment: {
service_code: service,
ship_to: { /* customer address */ },
ship_from: { /* warehouse address */ },
packages: [{
weight: convertedWeight,
dimensions: convertedDimensions,
}],
},
label_format: "PDF",
};
const response = await fetch(`${SHIPENGINE_API_URL}/labels`, {
method: "POST",
headers: {
"API-Key": provider.accessToken,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const result = await response.json();
return {
status: "purchased",
carrier: result.carrier_code,
service: result.service_type,
trackingNumber: result.tracking_number,
trackingUrl: result.tracking_url,
labelUrl: result.label_download.pdf,
};
}
Shipping Flow
Set up your shipping provider in the admin dashboard:
Navigate to Platform > Shipping Providers
Click Create Shipping Provider
Enter provider details and credentials
Configure warehouse/origin address
Select regions where this provider is available
Create shipping options for each region:
mutation {
createShippingOption(data: {
name: "Standard Shipping"
priceType: "calculated"
region: { connect: { id: "region_id" } }
provider: { connect: { id: "provider_id" } }
}) {
id
name
}
}
Calculate Rates at Checkout
Get real-time shipping rates for a cart:
query {
cart(where: { id: "cart_id" }) {
availableShippingMethods {
id
name
price
estimatedDays
}
}
}
Customer chooses their preferred shipping:
mutation {
setShippingMethod(
cartId: "cart_id"
shippingMethodId: "method_id"
) {
id
shippingMethod {
name
price
}
}
}
After order placement, create shipping label:
mutation {
createShippingLabel(
orderId: "order_id"
fulfillmentId: "fulfillment_id"
dimensions: {
length: 10
width: 8
height: 6
weight: 2
unit: "in"
weightUnit: "lb"
}
) {
id
trackingNumber
trackingUrl
labelUrl
}
}
Package Dimensions
Dimensions are required for calculating accurate rates:
interface Dimensions {
length: number
width: number
height: number
weight: number
unit: "in" | "cm" | "m" | "ft" // Distance unit
weightUnit: "lb" | "oz" | "kg" | "g" // Weight unit
}
Openfront automatically:
- Stores default dimensions on product variants
- Calculates dimensions from cart items
- Converts units to provider requirements
Shipping Profiles
Group products with similar shipping requirements:
ShippingProfile {
name: string
type: "default" | "gift_card" | "digital"
products: [→ Product]
shippingOptions: [→ ShippingOption]
}
Use cases:
- Default: Physical products requiring shipping
- Gift Card: Digital delivery, no shipping
- Digital: Downloadable products
Address Validation
Validate addresses before creating labels:
const validation = await validateAddressFunction({
provider,
address: {
firstName: "John",
lastName: "Doe",
address1: "1234 Main St",
city: "San Francisco",
province: "CA",
postalCode: "94102",
country: { iso2: "US" },
},
});
if (!validation.isValid) {
console.log("Address errors:", validation.errors);
} else {
console.log("Validated address:", validation.suggestedAddress);
}
const validation = await validateAddressFunction({
provider,
address: {
firstName: "Jane",
lastName: "Smith",
address1: "500 5th Ave",
city: "New York",
province: "NY",
postalCode: "10110",
country: { iso2: "US" },
},
});
if (validation.isValid) {
console.log("Address is valid");
}
Tracking Shipments
Track shipment status and location:
const tracking = await trackShipmentFunction({
provider,
trackingNumber: "1Z999AA10123456784",
});
console.log(tracking.status);
console.log(tracking.events);
Creating Custom Shipping Adapters
Add custom shipping providers:
// features/integrations/shipping-providers/custom-carrier.ts
export async function getRatesFunction({ provider, order, dimensions }) {
// Call your carrier's API
const response = await fetch(`https://api.carrier.com/rates`, {
method: "POST",
headers: { "API-Key": provider.accessToken },
body: JSON.stringify({ /* rate request */ }),
});
const rates = await response.json();
return rates.map(rate => ({
id: rate.id,
providerId: provider.id,
service: rate.service,
carrier: rate.carrier,
price: rate.price,
currency: "USD",
estimatedDays: rate.transit_days,
}));
}
export async function createLabelFunction({ provider, order, rateId, dimensions }) {
// Generate shipping label
const response = await fetch(`https://api.carrier.com/labels`, {
method: "POST",
headers: { "API-Key": provider.accessToken },
body: JSON.stringify({ /* label request */ }),
});
const label = await response.json();
return {
status: "purchased",
trackingNumber: label.tracking_number,
labelUrl: label.label_url,
};
}
// Implement other required functions...
Register in features/integrations/shipping-providers/index.ts:
export const shippingProviderAdapters = {
shippo: () => import("./shippo"),
shipengine: () => import("./shipengine"),
manual: () => import("./manual"),
custom: () => import("./custom-carrier"),
};
Multi-Location Fulfillment
Manage inventory across multiple warehouses:
Location {
name: string
address: string
variants: [→ ProductVariant]
}
Openfront automatically:
- Routes orders to nearest fulfillment location
- Calculates shipping from correct origin
- Manages stock across locations
Best Practices
- Validate addresses before label creation
- Store dimensions on product variants
- Use calculated pricing for accurate rates
- Handle carrier errors gracefully
- Test with sandbox credentials
- Monitor webhook events for tracking updates