In today’s fast-paced e-commerce landscape, efficient shipping and order tracking systems are crucial for customer satisfaction. This comprehensive guide explores how to integrate the ExpoExpress API for creating shipments and tracking orders in a Node.js application using NestJS framework.
Understanding ExpoExpress API Integration
ExpoExpress is a prominent courier service provider that offers robust API solutions for shipment management. Their API enables developers to programmatically create shipments, calculate shipping rates, and track orders in real-time. The integration involves several key endpoints that work together to provide a complete shipping solution.
Setting Up ExpoExpress API Configuration
Before diving into the implementation, you’ll need to configure your environment variables for ExpoExpress API access:
// Environment Configuration
EXPO_EXPRESS_API_URL=https://developer.expoexpressnp.com/v1
EXPO_EXPRESS_API_KEY=your-api-key-here
These credentials are essential for authenticating with the ExpoExpress API and accessing their services.
Fetching Available Cities and Coverage Areas
The first step in any shipping integration is determining service availability. ExpoExpress provides endpoints to fetch supported cities and their coverage areas.
async getExpoCityList() {
try {
const response = await axios.get(
process.env.EXPO_EXPRESS_API_URL + '/Cities',
);
return response?.data?.Cities ?? [];
} catch (error) {
console.log(error);
throw new HttpException('Something went wrong', HttpStatus.BAD_REQUEST);
}
}
Retrieving Coverage Areas
async getExpoCoveredAreas(city: string) {
try {
let url = process.env.EXPO_EXPRESS_API_URL + '/CoveredAreas';
if (city) {
url += `/${city}`;
}
const response = await axios.get(url);
return response?.data?.CoveredAreas ?? [];
} catch (error) {
console.log(error);
throw new HttpException('Something went wrong', HttpStatus.BAD_REQUEST);
}
}
These functions allow your application to dynamically present available shipping destinations to customers during the checkout process.
Calculating Shipping Rates
Before creating a shipment, it’s essential to provide accurate shipping cost estimates to customers. The ExpoExpress API offers a rate calculation endpoint:
async calculateExpoExpressRate(city: string, area: string) {
try {
const url = process.env.EXPO_EXPRESS_API_URL + '/DomesticRateCalculation';
const payload = {
APIKEY: process.env.EXPO_EXPRESS_API_KEY,
DestinationAddress: {
City: city,
Area: area,
},
ShipmentDetails: {
Weight: 0.5,
DescriptionOfGoods: 'Baby Food, Document',
GoodsValue: 1000.0,
NumberOfPieces: 1,
ProductGroup: 'Document',
ServiceType: 'ONP',
},
};
const response = await axios.post(url, payload);
return response?.data?.rateDetails
? response.data.rateDetails[0]
: { error: 'No rate details found' };
} catch (error) {
console.log(error, error.response?.data);
throw new HttpException('Something went wrong', HttpStatus.BAD_REQUEST);
}
}
This function calculates shipping costs based on destination and shipment details, enabling dynamic pricing for your customers.
Creating ExpoExpress Shipments
The core functionality involves creating shipments when orders are placed. Here’s how to implement the shipment creation process:
async createExpoExpressShipment(
orderId: string,
order:any,
city:string,
area:string
) {
try {
const url = process.env.EXPO_EXPRESS_API_URL + '/CreateShipments';
const payload = {
APIKEY: process.env.EXPO_EXPRESS_API_KEY,
Shipments: [
{
ServiceType: 'ONP',
Reference: orderId,
PrimaryPhoneNo:order.address.mobile,
OptionalPhoneNo: order.customerAlternateMobile,
CustomerName: order.customerName,
CustomerEmail: 'odr-' + orderId + '@bwishernepal.com',
City: city,
Area: area,
Landmark: order.customerAddress,
PackageType: 'PARCEL',
GoodsValue: order.postpaidAmount,
TotalWeight: 0.5,
ProductCode: 'PROD001',
CODAmount: order.postpaidAmount,
DeliveryInstruction: 'Leave at the front desk',
},
],
};
console.log('expo express payload', payload);
const response = await axios.post(url, payload);
console.log('expo express response', response?.data);
const shipment = response?.data?.data?.shipments?.[0];
if (!shipmentId) {
throw new HttpException(
'Failed to create shipment, please contact the admin',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
return shipment;
} catch (error) {
console.log(error);
throw new HttpException(
error?.message ?? 'Failed to connect with expo express service',
error.status ?? HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
This comprehensive function handles the entire shipment creation process, from validating the order to storing shipment details and updating delivery status.
Implementing Order Tracking
Real-time order tracking is essential for customer satisfaction. ExpoExpress provides a tracking endpoint that returns detailed shipment status information:
async ExpoExpressTracking(trackingId: string) {
try {
const data = {
APIKEY: process.env.EXPO_EXPRESS_API_KEY,
Shipments: [trackingId],
GetLastTrackingUpdateOnly: true,
};
const url = process.env.EXPO_EXPRESS_API_URL + '/TrackShipments';
const response = await axios.post(url, data);
if (response.data != null || response.data != undefined) {
console.log('Shipment Tracking Details:', response.data);
return response.data;
} else {
return {
message: 'No tracking details found for this shipment',
};
}
} catch (e) {
throw new HttpException(e ?? e.message, e.status || 500);
}
}
REST API Endpoints for Frontend Integration
To complete the integration, expose these functions through REST API endpoints that your frontend can consume:
@Controller('shipment')
export class ShipmentController {
constructor(private readonly shipmentService: ShipmentService) {}
@Get('expo/cities')
async getExpoCityList() {
try {
return await this.shipmentService.getExpoCityList();
} catch {
throw new HttpException(
'Something went wrong, please try again later',
HttpStatus.BAD_REQUEST,
);
}
}
@Get('expo/covered-areas')
async getExpoCoveredAreas(@Query('city') city: string) {
try {
if (!city || typeof city !== 'string') {
throw new HttpException(
'City parameter is required and must be a string',
HttpStatus.BAD_REQUEST,
);
}
const sanitizedCity = city.trim().replace(/[^a-zA-Z0-9\s-_]/g, '');
if (!sanitizedCity) {
throw new HttpException(
'Invalid city parameter',
HttpStatus.BAD_REQUEST,
);
}
return await this.shipmentService.getExpoCoveredAreas(sanitizedCity);
} catch (error) {
throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
}
}
@Get('expo/shipping-cost')
async calculateExpoShipmentCost(
@Query('city') city: string,
@Query('area') area: string,
) {
try {
if (!city || !area) {
throw new HttpException(
'City and area are required',
HttpStatus.BAD_REQUEST,
);
}
return await this.shipmentService.calculateExpoExpressRate(city, area);
} catch (error) {
throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
}
}
@Post('expo/create-shipment/:orderId')
async createExpoExpressShipment(
@Body() createShipmentInput: CreateExpoExpressShipment,
@Param('orderId') orderId: string,
) {
try {
return await this.shipmentService.createExpoExpressShipment(
orderId,
createShipmentInput,
);
} catch (error) {
throw new HttpException(
error.message ?? 'Something went wrong',
error.status ?? HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
@Get('expo/track-shipment/:trackingNumber')
async trackExpoExpressShipment(
@Param('trackingNumber') trackingNumber: string,
) {
try {
return await this.shipmentService.ExpoExpressTracking(trackingNumber);
} catch (error) {
throw new HttpException(
error.message ?? 'Something went wrong',
error.status ?? HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
}
Best Practices for ExpoExpress Integration
When implementing ExpoExpress API integration, consider these important practices:
Error Handling: Always implement comprehensive error handling to gracefully manage API failures and provide meaningful feedback to users.
Data Validation: Validate all input data before sending requests to the ExpoExpress API to prevent errors and ensure data integrity.
Rate Limiting: Implement appropriate rate limiting to avoid overwhelming the ExpoExpress API servers.
Logging: Maintain detailed logs of all API interactions for debugging and monitoring purposes.
Security: Never expose API keys in client-side code and always use environment variables for sensitive configuration.
Conclusion
Integrating ExpoExpress API into your e-commerce application provides a robust shipping solution that enhances customer experience through accurate rate calculations, seamless shipment creation, and real-time order tracking. The implementation shown above demonstrates a complete integration that handles all aspects of the shipping workflow, from initial rate calculation to final delivery confirmation.
By following this implementation guide, you can create a reliable shipping system that scales with your business needs while providing customers with the transparency and reliability they expect from modern e-commerce platforms. The combination of proper error handling, automated status updates, and comprehensive API coverage ensures a smooth shipping experience for both merchants and customers.