Building an International Shipping Platform with FedEx API and Stripe
How we built ShipAnywhere, a full-stack shipping platform integrating FedEx rates, label generation, Stripe wallets, and Shopify order sync.
The Challenge
Small e-commerce merchants in Southeast Asia face a common problem: international shipping is expensive and complicated. They need to compare rates, generate labels, track packages, and manage shipping costs — all while keeping their Shopify store in sync. ShipAnywhere was built to solve exactly this.
Architecture Overview
ShipAnywhere is a Node.js/Express application backed by PostgreSQL, deployed on Railway. It connects three major external services:
- FedEx API — real-time rate quotes and label generation
- Stripe — prepaid wallet system for shipping credits
- Shopify API — order import and fulfillment tracking
The Wallet Model
Rather than charging per shipment via credit card (which adds friction and processing fees), ShipAnywhere uses a prepaid wallet system. Merchants top up their balance via Stripe, and shipping costs are deducted from the wallet. This approach:
- Reduces per-transaction payment fees
- Enables instant label generation without payment delays
- Simplifies refunds when shipments are cancelled
FedEx API Integration
FedEx's REST API replaced their legacy SOAP services. Here's how we handle rate shopping:
async function getRates(shipment) {
const token = await getFedExToken();
const response = await axios.post(
`${FEDEX_BASE_URL}/rate/v1/rates/quotes`,
{
accountNumber: { value: FEDEX_ACCOUNT },
requestedShipment: {
shipper: formatAddress(shipment.from),
recipient: formatAddress(shipment.to),
requestedPackageLineItems: [{
weight: { value: shipment.weight, units: 'KG' },
dimensions: {
length: shipment.length,
width: shipment.width,
height: shipment.height,
units: 'CM'
}
}]
}
},
{ headers: { Authorization: `Bearer ${token}` } }
);
return response.data.output.rateReplyDetails.map(rate => ({
service: rate.serviceName,
deliveryDays: rate.commit?.dateDetail?.dayFormat,
cost: rate.ratedShipmentDetails[0].totalNetCharge
}));
}
Token Management
FedEx OAuth tokens expire after 60 minutes. We cache them in memory with a buffer:
let cachedToken = null;
let tokenExpiry = 0;
async function getFedExToken() {
if (cachedToken && Date.now() < tokenExpiry - 60000) {
return cachedToken;
}
const response = await axios.post(`${FEDEX_BASE_URL}/oauth/token`, {
grant_type: 'client_credentials',
client_id: FEDEX_CLIENT_ID,
client_secret: FEDEX_CLIENT_SECRET
});
cachedToken = response.data.access_token;
tokenExpiry = Date.now() + (response.data.expires_in * 1000);
return cachedToken;
}
Shopify Order Sync
When a merchant connects their Shopify store, ShipAnywhere imports unfulfilled orders and listens for new ones via webhooks. After a label is generated, the app automatically:
- Marks the Shopify order as fulfilled
- Adds the FedEx tracking number
- Triggers Shopify's shipping confirmation email
This eliminates the manual copy-paste workflow that merchants were doing before.
Document Storage with Cloudflare R2
Shipping labels and commercial invoices are stored in Cloudflare R2, an S3-compatible object store. R2 was chosen over AWS S3 for its zero egress fees — since labels are downloaded frequently, this saved significant costs.
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const r2Client = new S3Client({
region: 'auto',
endpoint: process.env.R2_ENDPOINT,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY,
secretAccessKey: process.env.R2_SECRET_KEY
}
});
async function uploadLabel(buffer, filename) {
await r2Client.send(new PutObjectCommand({
Bucket: process.env.R2_BUCKET,
Key: `labels/${filename}`,
Body: buffer,
ContentType: 'application/pdf'
}));
}
Key Technical Decisions
- PostgreSQL over MongoDB — shipping data is highly relational (orders, shipments, addresses, invoices)
- Railway over AWS — faster deployment cycles for a small team, built-in PostgreSQL
- Prepaid wallet over per-transaction billing — reduced Stripe fees and better UX
- Cloudflare R2 over S3 — zero egress fees for frequently accessed labels
Results
ShipAnywhere reduced the time from order receipt to label generation from 15+ minutes (manual process) to under 30 seconds. Merchants can now batch-process dozens of shipments and have all labels ready in minutes.
Related Project
ShipAnywhereSmart international shipping platform offering up to 60% off FedEx rates, with instant quotes, one-click labels, electronic trade documents, and scheduled pickups to 220+ countries.