Shippo
Shippo : API-first shipping platform avec 85+ transporteurs. Solution developer-friendly pour intégration shipping multi-carrier.
📚 Ressources Complémentaires
📖 Guides Pratiques
⚖️ Comparatifs
Shippo : API-First Shipping Simplified
Qu’est-ce que Shippo ?
Shippo est la plateforme shipping API-first utilisée par 15k+ développeurs et e-commerce platforms. Cette solution San Francisco-based focus sur developer experience avec architecture clean, 85+ carriers integration, pricing transparent et webhooks reliable pour teams building shipping solutions.
🚀 Fonctionnalités Principales
API-First Architecture
- RESTful API : endpoints clear, documentation comprehensive
- 85+ carriers : USPS, FedEx, UPS, DHL, regional
- Rate shopping : real-time comparison automated
- Label generation : PDF, PNG formats multiple sizes
Developer Experience
- SDKs multiple : Python, Node.js, PHP, Ruby, Go
- Webhooks reliable : tracking updates, delivery status
- Sandbox environment : testing complete integration
- Rate limiting : generous quotas development
Multi-Carrier Management
- Account management : multiple carrier accounts unified
- Service mapping : standardized service names
- Error handling : consistent responses cross-carriers
- Batch operations : bulk processing efficient
Tracking & Notifications
- Universal tracking : all carriers unified interface
- Real-time webhooks : instant status updates
- Customer notifications : SMS, email automated
- Delivery confirmation : signature, photo proof
💰 Prix et Structure
Free Plan (Starter)
- 100 shipments/month : perfect small projects
- All carriers : full network access
- Basic support : email community forum
- Standard features : rate shopping, tracking
Professional : $19/mois
- 1000 shipments/month : growing businesses
- Priority support : 24h response time
- Advanced features : batch operations, returns
- Analytics dashboard : performance insights
Plus : $49/mois
- 5000 shipments/month : scale operations
- Phone support : dedicated success team
- Custom integrations : webhook priorities
- White-label options : branded tracking
Enterprise : Custom
- Unlimited shipments : volume discounts
- SLA guarantees : 99.9% uptime
- Account management : dedicated support
- Custom development : specialized features
⭐ Points Forts
🔧 Developer Experience
API excellence :
- Clean RESTful design standards
- Comprehensive documentation interactive
- SDKs actively maintained
- Sandbox environment realistic
💰 Pricing Transparency
Cost structure simple :
- Per-label pricing clear
- No hidden fees setup
- Volume discounts automatic
- Carrier costs transparent
⚡ Performance & Reliability
Infrastructure robust :
- 99.9% uptime SLA
- Global CDN label delivery
- Webhook delivery guaranteed
- Rate limiting generous
🌐 Carrier Network
Multi-carrier coverage :
- USPS commercial rates access
- International carriers included
- Regional specialists supported
- New carriers added regularly
⚠️ Points Faibles
🎨 Interface Basique
Dashboard limitations :
- Basic UI vs competitors
- Limited customization options
- Analytics basic reporting
- Bulk operations interface clunky
🚀 Features Avancées
Advanced functionality gaps :
- Customs automation basic
- Return management simple
- Inventory integration limited
- Advanced routing missing
📞 Support Tiers
Customer support limitations :
- Free tier email only
- Response times tier-dependent
- Phone support premium plans
- Documentation gaps edge cases
🌍 International Focus
Global shipping limitations :
- Customs features basic
- International carriers fewer
- Duty/tax calculation manual
- Local expertise limited
🎯 Pour Qui ?
✅ Parfait Pour
- Développeurs API-first integration
- Startups tech clean architecture needs
- Scale-ups 100-5000 shipments/month
- SaaS platforms embedding shipping
- Budget-conscious transparent pricing
❌ Moins Adapté Pour
- Non-technical users preferring UI
- Complex international shipping needs
- Enterprise advanced features requirements
- High-touch support expectations
- Advanced automation workflow needs
📊 Shippo vs Developer-Focused Platforms
| Critère | Shippo | EasyPost | ShipEngine |
|---|---|---|---|
| API Design | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Pricing Transparency | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| Carrier Network | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Advanced Features | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Free Tier Value | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
🛠️ Configuration & Intégration
Shippo Node.js SDK
// Shippo API integration
const shippo = require('shippo')(process.env.SHIPPO_API_TOKEN);
class ShippoService {
constructor() {
this.apiToken = process.env.SHIPPO_API_TOKEN;
this.environment = process.env.SHIPPO_ENVIRONMENT || 'production';
}
async createAddressFrom(addressData) {
try {
const address = await shippo.address.create({
name: addressData.name,
company: addressData.company,
street1: addressData.street1,
street2: addressData.street2,
city: addressData.city,
state: addressData.state,
zip: addressData.zip,
country: addressData.country,
phone: addressData.phone,
email: addressData.email,
is_residential: addressData.isResidential || false
});
// Validate address if needed
if (!address.is_valid) {
console.warn('Address validation issues:', address.messages);
}
return address;
} catch (error) {
console.error('Address creation failed:', error);
throw new Error('Invalid address data provided');
}
}
async getRates(shipmentData) {
try {
const shipment = await shippo.shipment.create({
address_from: shipmentData.addressFrom,
address_to: shipmentData.addressTo,
parcels: shipmentData.parcels,
extra: {
insurance: {
amount: shipmentData.insurance?.amount || 0,
currency: shipmentData.insurance?.currency || 'USD'
}
}
});
// Filter and sort rates
const availableRates = shipment.rates
.filter(rate => !rate.messages.length)
.sort((a, b) => parseFloat(a.amount) - parseFloat(b.amount));
return {
shipmentId: shipment.object_id,
rates: availableRates.map(rate => ({
rateId: rate.object_id,
carrier: rate.provider,
service: rate.servicelevel.name,
amount: parseFloat(rate.amount),
currency: rate.currency,
estimatedDays: rate.estimated_days,
durationTerms: rate.duration_terms
}))
};
} catch (error) {
console.error('Rate calculation failed:', error);
throw new Error('Unable to calculate shipping rates');
}
}
async purchaseLabel(rateId, labelFormat = 'PDF') {
try {
const transaction = await shippo.transaction.create({
rate: rateId,
label_file_type: labelFormat,
async: false
});
if (transaction.status === 'SUCCESS') {
return {
labelUrl: transaction.label_url,
trackingNumber: transaction.tracking_number,
trackingUrl: transaction.tracking_url_provider,
transactionId: transaction.object_id,
carrier: transaction.rate.provider,
service: transaction.rate.servicelevel.name
};
} else {
throw new Error(`Label purchase failed: ${transaction.messages.join(', ')}`);
}
} catch (error) {
console.error('Label purchase failed:', error);
throw new Error('Unable to purchase shipping label');
}
}
async trackShipment(carrier, trackingNumber) {
try {
const track = await shippo.track.get_status(carrier, trackingNumber);
return {
carrier: track.carrier,
trackingNumber: track.tracking_number,
status: track.tracking_status,
statusDetails: track.tracking_status.status_details,
eta: track.eta ? new Date(track.eta) : null,
events: track.tracking_history.map(event => ({
status: event.status,
statusDetails: event.status_details,
location: `${event.location.city}, ${event.location.state}`,
timestamp: new Date(event.status_date)
}))
};
} catch (error) {
console.error('Tracking failed:', error);
throw new Error('Unable to retrieve tracking information');
}
}
async createReturn(originalTransactionId, returnAddress) {
try {
// Get original transaction details
const originalTransaction = await shippo.transaction.get(originalTransactionId);
// Create return shipment
const returnShipment = await shippo.shipment.create({
address_from: returnAddress,
address_to: originalTransaction.rate.shipment.address_from,
parcels: originalTransaction.rate.shipment.parcels,
extra: {
is_return: true,
reference_1: `RETURN_${originalTransactionId}`
}
});
// Select cheapest rate for returns
const cheapestRate = returnShipment.rates
.filter(rate => !rate.messages.length)
.sort((a, b) => parseFloat(a.amount) - parseFloat(b.amount))[0];
if (!cheapestRate) {
throw new Error('No available return rates found');
}
// Purchase return label
const returnTransaction = await shippo.transaction.create({
rate: cheapestRate.object_id,
label_file_type: 'PDF'
});
return {
returnLabelUrl: returnTransaction.label_url,
returnTrackingNumber: returnTransaction.tracking_number,
returnTrackingUrl: returnTransaction.tracking_url_provider,
carrier: returnTransaction.rate.provider,
service: returnTransaction.rate.servicelevel.name
};
} catch (error) {
console.error('Return creation failed:', error);
throw new Error('Unable to create return shipment');
}
}
async validateAddress(addressData) {
try {
const address = await this.createAddressFrom(addressData);
return {
isValid: address.is_valid,
validationMessages: address.messages || [],
correctedAddress: address.is_valid ? {
name: address.name,
company: address.company,
street1: address.street1,
street2: address.street2,
city: address.city,
state: address.state,
zip: address.zip,
country: address.country
} : null
};
} catch (error) {
return {
isValid: false,
validationMessages: ['Address validation failed'],
correctedAddress: null
};
}
}
// Webhook handling
setupWebhookHandler(app) {
app.post('/webhook/shippo/tracking', (req, res) => {
const event = req.body;
try {
this.handleTrackingUpdate(event);
res.status(200).send('OK');
} catch (error) {
console.error('Webhook processing failed:', error);
res.status(500).send('Error processing webhook');
}
});
}
handleTrackingUpdate(event) {
const { carrier, tracking_number, tracking_status } = event.data;
console.log(`Tracking update: ${carrier} ${tracking_number} - ${tracking_status.status}`);
// Process tracking update based on status
switch (tracking_status.status) {
case 'DELIVERED':
this.handleDeliveryConfirmation(event.data);
break;
case 'FAILURE':
this.handleDeliveryFailure(event.data);
break;
case 'RETURNED':
this.handleReturnToSender(event.data);
break;
default:
this.handleTrackingProgress(event.data);
}
}
handleDeliveryConfirmation(trackingData) {
// Update order status, send confirmation emails, etc.
console.log('Package delivered:', trackingData);
}
handleDeliveryFailure(trackingData) {
// Handle failed delivery, create return label, notify customer
console.log('Delivery failed:', trackingData);
}
}
// Usage example
const shippoService = new ShippoService();
async function processOrder(orderData) {
try {
// Create addresses
const addressFrom = await shippoService.createAddressFrom(orderData.sender);
const addressTo = await shippoService.createAddressFrom(orderData.recipient);
// Calculate rates
const shipmentData = {
addressFrom: addressFrom.object_id,
addressTo: addressTo.object_id,
parcels: [{
length: orderData.package.length,
width: orderData.package.width,
height: orderData.package.height,
distance_unit: 'in',
weight: orderData.package.weight,
mass_unit: 'lb'
}],
insurance: {
amount: orderData.declaredValue,
currency: 'USD'
}
};
const rates = await shippoService.getRates(shipmentData);
// Select rate (e.g., cheapest or fastest)
const selectedRate = rates.rates[0];
// Purchase label
const label = await shippoService.purchaseLabel(selectedRate.rateId);
console.log('Shipping label created:', label);
return {
success: true,
tracking: label.trackingNumber,
labelUrl: label.labelUrl,
carrier: label.carrier,
service: label.service
};
} catch (error) {
console.error('Order processing failed:', error);
return {
success: false,
error: error.message
};
}
}
Express.js Integration Complete
// Complete Express.js integration with Shippo
const express = require('express');
const bodyParser = require('body-parser');
class ShippoExpressApp {
constructor() {
this.app = express();
this.shippo = new ShippoService();
this.setupMiddleware();
this.setupRoutes();
}
setupMiddleware() {
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: true }));
// Error handling middleware
this.app.use((err, req, res, next) => {
console.error('Express error:', err);
res.status(500).json({ error: 'Internal server error' });
});
}
setupRoutes() {
// Address validation endpoint
this.app.post('/api/shippo/validate-address', async (req, res) => {
try {
const validation = await this.shippo.validateAddress(req.body);
res.json(validation);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
// Get shipping rates
this.app.post('/api/shippo/rates', async (req, res) => {
try {
const rates = await this.shippo.getRates(req.body);
res.json(rates);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
// Purchase shipping label
this.app.post('/api/shippo/purchase', async (req, res) => {
try {
const { rateId, labelFormat } = req.body;
const label = await this.shippo.purchaseLabel(rateId, labelFormat);
res.json(label);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
// Track shipment
this.app.get('/api/shippo/track/:carrier/:trackingNumber', async (req, res) => {
try {
const { carrier, trackingNumber } = req.params;
const tracking = await this.shippo.trackShipment(carrier, trackingNumber);
res.json(tracking);
} catch (error) {
res.status(404).json({ error: error.message });
}
});
// Create return label
this.app.post('/api/shippo/returns', async (req, res) => {
try {
const { originalTransactionId, returnAddress } = req.body;
const returnLabel = await this.shippo.createReturn(originalTransactionId, returnAddress);
res.json(returnLabel);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
// Webhook endpoint
this.shippo.setupWebhookHandler(this.app);
}
start(port = 3000) {
this.app.listen(port, () => {
console.log(`Shippo API server running on port ${port}`);
});
}
}
// Start the application
const app = new ShippoExpressApp();
app.start();
🏆 Notre Verdict
Shippo excellent choix développeurs cherchant API-first shipping clean et pricing transparent. Developer experience outstanding, mais features advanced limited vs competitors.
Note Globale : 4.0/5 ⭐⭐⭐⭐
- Developer Experience : 5/5
- API Quality : 5/5
- Pricing Transparency : 5/5
- Feature Completeness : 3/5
- Customer Support : 3/5
🎯 Cas d’Usage Réels
💡 Exemple : SaaS E-commerce Platform
Embedded shipping solution :
- White-label API : customer-branded tracking
- Multi-tenant : separate carrier accounts
- Webhook reliability : real-time status updates
- SDK integration : rapid development
💡 Exemple : Subscription Box Service
Recurring shipping automation :
- Monthly fulfillment : batch processing efficient
- Customer experience : tracking notifications automated
- Cost optimization : rate shopping automatic
- Returns handling : simplified process
💡 Conseil OSCLOAD : Shippo ideal choice développeurs API-first architecture. Free tier généreux testing, pricing transparent scale. Alternative EasyPost features advanced ou ShipStation non-technical users.