API integrationdeveloper guideshipping API

Shipping API Integration: Developer Guide for E-commerce Platforms

Technical guide to integrating shipping APIs into your e-commerce platform. Authentication, rate shopping, label generation, and webhook handling.

January 9, 20265 min read36 views
Shipping API Integration: Developer Guide for E-commerce Platforms

Shipping API Integration Overview

Integrating shipping APIs enables automated rate shopping, label generation, and tracking. This guide covers best practices for developers building shipping functionality.

API Architecture Patterns

Direct Carrier Integration

CarrierAPI StyleAuth Method
USPSREST/XMLUser ID
UPSRESTOAuth 2.0
FedExRESTOAuth 2.0
DHLRESTAPI Key
ProviderCarriersSingle API
AtoshipUSPS, UPS, FedEx, DHLYes
EasyPostMultipleYes
ShipEngineMultipleYes
Benefit: Single integration, multiple carriers

Authentication Implementation

OAuth 2.0 Flow (UPS/FedEx)

// OAuth token request
const getToken = async () => {
  const response = await fetch('https://api.carrier.com/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': 'Basic ' + btoa(clientId + ':' + clientSecret)
    },
    body: 'grant_type=client_credentials'
  });
  return response.json();
};

API Key Authentication

// API key in headers
const headers = {
  'Authorization': 'Bearer YOUR_API_KEY',
  'Content-Type': 'application/json'
};

Token Refresh Strategy

StrategyImplementation
Pre-emptive refreshRefresh 5 min before expiry
On-error refreshRefresh on 401 response
Sliding windowRefresh on each request

Rate Shopping Implementation

Request Structure

{
  "from_address": {
    "name": "Sender",
    "street1": "123 Main St",
    "city": "New York",
    "state": "NY",
    "zip": "10001",
    "country": "US"
  },
  "to_address": {
    "name": "Recipient",
    "street1": "456 Oak Ave",
    "city": "Los Angeles",
    "state": "CA",
    "zip": "90001",
    "country": "US"
  },
  "parcel": {
    "length": 10,
    "width": 8,
    "height": 4,
    "weight": 32
  }
}

Response Handling

// Parse rate response
const selectBestRate = (rates) => {
  // Sort by price
  const sorted = rates.sort((a, b) => a.rate - b.rate);

// Filter by service level const groundRates = sorted.filter(r => r.service.includes('ground') || r.service.includes('standard') );

return groundRates[0] || sorted[0]; };

Label Generation

Create Shipment Request

{
  "shipment": {
    "from_address": { / address object / },
    "to_address": { / address object / },
    "parcel": { / parcel object / },
    "carrier": "usps",
    "service": "ground_advantage"
  },
  "options": {
    "label_format": "PDF",
    "label_size": "4x6"
  }
}

Response Processing

// Handle label response
const processLabel = async (shipmentId) => {
  const response = await createShipment(shipmentData);

return { trackingNumber: response.tracking_code, labelUrl: response.label_url, labelBase64: response.label_base64, rate: response.rate, carrier: response.carrier }; };

Batch Label Generation

// Process multiple labels
const batchCreateLabels = async (orders) => {
  const promises = orders.map(order =>
    createShipment(order).catch(err => ({ error: err, orderId: order.id }))
  );

const results = await Promise.allSettled(promises);

return { successful: results.filter(r => r.status === 'fulfilled'), failed: results.filter(r => r.status === 'rejected') }; };

Webhook Integration

Tracking Webhooks

// Webhook endpoint
app.post('/webhooks/tracking', async (req, res) => {
  const event = req.body;

// Verify webhook signature if (!verifySignature(req)) { return res.status(401).send('Invalid signature'); }

// Process tracking update switch (event.type) { case 'tracker.updated': await updateOrderTracking(event.data); break; case 'tracker.delivered': await markOrderDelivered(event.data); break; }

res.status(200).send('OK'); });

Webhook Event Types

EventDescription
tracker.createdTracking initiated
tracker.updatedStatus changed
tracker.deliveredPackage delivered
tracker.exceptionDelivery issue

Error Handling

Common Error Codes

CodeMeaningAction
400Bad requestValidate input
401UnauthorizedRefresh token
404Not foundCheck resource ID
429Rate limitedImplement backoff
500Server errorRetry with backoff

Retry Strategy

const retryWithBackoff = async (fn, maxRetries = 3) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (err) {
      if (i === maxRetries - 1) throw err;
      if (err.status === 429 || err.status >= 500) {
        await sleep(Math.pow(2, i) * 1000);
      } else {
        throw err;
      }
    }
  }
};

Address Validation

Validation Request

{
  "address": {
    "street1": "123 Main Street",
    "city": "New York",
    "state": "NY",
    "zip": "10001",
    "country": "US"
  }
}

Validation Response Handling

const validateAndCorrect = async (address) => {
  const result = await validateAddress(address);

if (result.verifications.delivery.success) { return { valid: true, corrected: result.address, changes: result.verifications.delivery.details }; }

return { valid: false, errors: result.verifications.delivery.errors }; };

Rate Caching Strategy

Cache Implementation

const getRates = async (shipment) => {
  const cacheKey = generateCacheKey(shipment);

// Check cache const cached = await cache.get(cacheKey); if (cached && !isExpired(cached)) { return cached.rates; }

// Fetch fresh rates const rates = await fetchRates(shipment);

// Cache for 15 minutes await cache.set(cacheKey, { rates, timestamp: Date.now() }, 900);

return rates; };

Cache Key Generation

const generateCacheKey = (shipment) => {
  const { from, to, parcel } = shipment;
  return rates:${from.zip}:${to.zip}:${parcel.weight}:${parcel.length}x${parcel.width}x${parcel.height};
};

Testing and Sandbox

Sandbox Environments

ProviderSandbox URLTest Data
UPSwwwcie.ups.comTest credentials
FedExwsbeta.fedex.comTest credentials
USPSstg-production.shippingapis.comTest user ID

Integration Testing

describe('Shipping API', () => {
  it('should return rates for valid shipment', async () => {
    const rates = await getRates(testShipment);
    expect(rates.length).toBeGreaterThan(0);
    expect(rates[0].rate).toBeGreaterThan(0);
  });

it('should create label successfully', async () => { const label = await createLabel(testShipment); expect(label.trackingNumber).toBeDefined(); expect(label.labelUrl).toBeDefined(); }); });

Atoship API Advantages

FeatureBenefit
Single integrationAll carriers via one API
Pre-negotiated ratesCommercial pricing included
Unified response formatConsistent data structure
Sandbox environmentTest before production
Webhook supportReal-time tracking updates

Get Started with Atoship API

Sign up for Atoship and access our developer-friendly shipping API with comprehensive documentation.

Share this article:

Ready to save on shipping?

Get started with Atoship for free and access discounted USPS, UPS, and FedEx rates. No monthly fees, no contracts.

Create Free Account