
Introduction
In today’s e-commerce landscape, efficient shipping and logistics management is crucial for business success. Aramex, one of the leading logistics providers in the Middle East and South Asia, offers robust APIs that allow developers to integrate shipping functionalities directly into their applications. This comprehensive guide will walk you through implementing the Aramex API in a Node.js application, covering everything from initial setup to order creation and tracking.
Whether you’re building an e-commerce platform, marketplace, or any application that requires shipping integration, this step-by-step tutorial will provide you with the knowledge and practical implementation details needed to successfully integrate Aramex services into your Node.js application.
What is Aramex API?
Aramex provides a comprehensive set of RESTful APIs and SOAP web services that enable developers to access their shipping and logistics services programmatically. The API suite includes:
- Shipping API: Create shipments, calculate rates, and generate shipping labels
- Tracking API: Track shipments in real-time and get delivery status updates
- Location Services: Get cities, countries, and service availability information
- Rate Calculator: Calculate shipping costs based on origin, destination, and package details
Key Benefits of Aramex API Integration
- Automated Shipping Process: Streamline order fulfillment by automatically creating shipments
- Real-time Tracking: Provide customers with live tracking information
- Cost Calculation: Get accurate shipping rates before order confirmation
- Label Generation: Automatically generate and print shipping labels
- Global Coverage: Access Aramex’s extensive network across multiple countries
Prerequisites and Setup
Before we dive into the implementation, ensure you have the following prerequisites:
System Requirements
- Node.js (version 14 or higher)
- npm or yarn package manager
- A valid Aramex developer account
- Basic understanding of JavaScript and Node.js
- Familiarity with REST APIs and HTTP requests
Required Dependencies
Let’s start by setting up our Node.js project and installing the necessary dependencies:
mkdir aramex-integration
cd aramex-integration
npm init -y
Install the required packages:
npm install axios dotenv express body-parser
npm install --save-dev nodemon
Project Structure
Create the following directory structure:
aramex-integration/
├── src/
│ ├── services/
│ │ ├── aramexService.js
│ │ └── trackingService.js
│ ├── controllers/
│ │ ├── shipmentController.js
│ │ └── trackingController.js
│ ├── utils/
│ │ └── helpers.js
│ └── app.js
├── .env
├── package.json
└── README.md
Environment Configuration
Create a .env
file in your project root to store your Aramex API credentials:
# Aramex API Configuration
ARAMEX_USERNAME=your_aramex_username
ARAMEX_PASSWORD=your_aramex_password
ARAMEX_ACCOUNTNUMBER=your_account_number (customer number , go to dashboard->account and find account number)
ARAMEX_ACCOUNTPIN=your_account_pin ( Call Aramex Support/team to get account pin)
ARAMEX_ACCOUNTENTITY=your_account_entity (your account registered city , like KTM,BRJ)
ARAMEX_ACCOUNTCOUNTRYCODE=your_country_code (use your country code like NP,IN)
ARAMEX_API_URL=https://ws.aramex.net/ShippingAPI.V2
ARAMEX_TRACKING_URL=https://ws.aramex.net/ShippingAPI.V2/Tracking
ARAMEX_CITYLIST_API_URL=https://ws.aramex.net/AramexWebApi/WebServices/Geo/GetCities
# Application Configuration
PORT=3000
NODE_ENV=development
Implementing the Aramex Service
Creating the Base Aramex Service
Let’s create the core service that will handle all Aramex API interactions. Create src/services/aramexService.js
:
const axios = require('axios');
require('dotenv').config();
class AramexService {
constructor() {
this.username = process.env.ARAMEX_USERNAME;
this.password = process.env.ARAMEX_PASSWORD;
this.accountNumber = process.env.ARAMEX_ACCOUNTNUMBER;
this.accountPin = process.env.ARAMEX_ACCOUNTPIN;
this.accountEntity = process.env.ARAMEX_ACCOUNTENTITY;
this.accountCountryCode = process.env.ARAMEX_ACCOUNTCOUNTRYCODE;
this.apiUrl = process.env.ARAMEX_API_URL;
this.trackingUrl = process.env.ARAMEX_TRACKING_URL;
this.cityListUrl = process.env.ARAMEX_CITYLIST_API_URL;
}
// Get client information object for API requests
getClientInfo() {
return {
UserName: this.username,
Password: this.password,
Version: 'v1',
AccountNumber: this.accountNumber,
AccountPin: this.accountPin,
AccountEntity: this.accountEntity,
AccountCountryCode: this.accountCountryCode,
Source: 24
};
}
// Format date for Aramex API
formatDate(date) {
return `\/Date(${date.getTime()})\/`;
}
// Clean phone number by removing country codes
cleanPhoneNumber(phoneNumber) {
if (!phoneNumber) return '';
return phoneNumber.toString()
.replace(/^\+?977/, '')
.replace(/^\+?91/, '')
.replace(/^977/, '')
.replace(/^91/, '')
.trim();
}
// Get list of cities from Aramex
async getCityList() {
try {
const response = await axios.get(this.cityListUrl);
return {
success: true,
data: response.data
};
} catch (error) {
console.error('Error fetching city list:', error.message);
return {
success: false,
error: 'Failed to fetch city list',
details: error.message
};
}
}
// Calculate shipping rate
async calculateRate(originAddress, destinationAddress, shipmentDetails) {
try {
const url = `${this.apiUrl}/RateCalculator/Service_1_0.svc/json/CalculateRate`;
const payload = {
ClientInfo: this.getClientInfo(),
OriginAddress: originAddress,
DestinationAddress: destinationAddress,
ShipmentDetails: shipmentDetails
};
const response = await axios.post(url, payload, {
headers: { 'Content-Type': 'application/json' }
});
if (response.data.HasErrors) {
throw new Error(response.data.Notifications[0].Message);
}
return {
success: true,
data: response.data
};
} catch (error) {
console.error('Error calculating rate:', error.message);
return {
success: false,
error: 'Failed to calculate shipping rate',
details: error.message
};
}
}
}
module.exports = AramexService;
Creating Shipments with Aramex API
Implementing the Shipment Creation Method
Add the following method to your AramexService
class:
// Create shipment
async createShipment(orderData) {
try {
const url = `${this.apiUrl}/shipping/Service_1_0.svc/json/CreateShipments`;
// Validate required order data
if (!orderData.customerName || !orderData.customerAddress || !orderData.customerMobile) {
throw new Error('Missing required customer information');
}
// Clean phone numbers
const cleanedPhone = this.cleanPhoneNumber(orderData.customerMobile);
const cleanedAlternatePhone = this.cleanPhoneNumber(orderData.customerAlternateMobile);
const shipmentPayload = {
ClientInfo: this.getClientInfo(),
LabelInfo: null,
Shipments: [{
Reference1: orderData.orderId || '',
Reference2: '',
Reference3: '',
Shipper: {
Reference1: '',
Reference2: '',
AccountNumber: this.accountNumber,
PartyAddress: {
Line1: orderData.shipperAddress.line1 ,
Line2: orderData.shipperAddress.line2 ,
Line3: orderData.shipperAddress.line3,
City: orderData.shipperAddress.city ,
StateOrProvinceCode: '',
PostCode: orderData.shipperAddress.postCode,
CountryCode: this.accountCountryCode,
Longitude: 0,
Latitude: 0,
BuildingNumber: null,
BuildingName: null,
Floor: null,
Apartment: null,
POBox: null,
Description: null
},
Contact: {
Department: orderData.shipperInfo.department,
PersonName: orderData.shipperInfo.name,
Title: '',
CompanyName: orderData.shipperInfo.company,
PhoneNumber1: orderData.shipperInfo.phone,
PhoneNumber1Ext: '',
PhoneNumber2: '',
PhoneNumber2Ext: '',
FaxNumber: '',
CellPhone: orderData.shipperInfo.mobile',
EmailAddress: orderData.shipperInfo.email',
Type: ''
}
},
Consignee: {
Reference1: '',
Reference2: '',
AccountNumber: this.accountNumber,
PartyAddress: {
Line1: orderData.customerAddress,
Line2: '',
Line3: '',
City: orderData.city,
StateOrProvinceCode: '',
PostCode: orderData.pincode || '',
CountryCode: this.accountCountryCode,
Longitude: 0,
Latitude: 0,
BuildingNumber: '',
BuildingName: '',
Floor: '',
Apartment: '',
POBox: null,
Description: ''
},
Contact: {
Department: orderData.customerName,
PersonName: orderData.customerName,
Title: '',
CompanyName: orderData.customerName,
PhoneNumber1: cleanedPhone,
PhoneNumber1Ext: '',
PhoneNumber2: cleanedAlternatePhone,
PhoneNumber2Ext: '',
FaxNumber: '',
CellPhone: cleanedPhone,
EmailAddress: orderData.customerEmail || `order-${orderData.orderId}@yourcompany.com`,
Type: ''
}
},
ThirdParty: {
Reference1: '',
Reference2: '',
AccountNumber: '',
PartyAddress: {
Line1: '', Line2: '', Line3: '', City: '',
StateOrProvinceCode: '', PostCode: '', CountryCode: '',
Longitude: 0, Latitude: 0, BuildingNumber: null,
BuildingName: null, Floor: null, Apartment: null,
POBox: null, Description: null
},
Contact: {
Department: '', PersonName: '', Title: '', CompanyName: '',
PhoneNumber1: '', PhoneNumber1Ext: '', PhoneNumber2: '',
PhoneNumber2Ext: '', FaxNumber: '', CellPhone: '',
EmailAddress: '', Type: ''
}
},
ShippingDateTime: this.formatDate(new Date()),
DueDate: this.formatDate(new Date()),
Comments: orderData.comments || '',
PickupLocation: '',
OperationsInstructions: '',
AccountingInstrcutions: '',
Details: {
Dimensions: null,
ActualWeight: {
Unit: 'KG',
Value: orderData.weight || 0.5
},
ChargeableWeight: null,
DescriptionOfGoods: orderData.productDescription || 'General Merchandise',
GoodsOriginCountry: this.accountCountryCode,
NumberOfPieces: orderData.quantity || 1,
ProductGroup: 'DOM',
ProductType: 'SMP',
ParcelContents: orderData.productDescription || 'General Merchandise',
PaymentType: 'P',
PaymentOptions: {},
CustomsValueAmount: {
CurrencyCode: orderData.currency || 'NPR',
Value: orderData.totalAmount || 0
},
CashOnDeliveryAmount: {
CurrencyCode: orderData.currency || 'NPR',
Value: orderData.codAmount || orderData.totalAmount || 0
},
InsuranceAmount: null,
CashAdditionalAmount: null,
CashAdditionalAmountDescription: null,
CollectAmount: null,
Services: orderData.codAmount ? 'CODS' : '',
Items: []
},
Attachments: [],
ForeignHAWB: '',
TransportType: 0,
PickupGUID: '',
Number: null,
ScheduledDelivery: null
}],
Transaction: {
Reference1: '', Reference2: '', Reference3: '',
Reference4: '', Reference5: ''
}
};
const response = await axios.post(url, shipmentPayload, {
headers: { 'Content-Type': 'application/json' }
});
if (response.data.HasErrors) {
throw new Error(response.data.Notifications[0].Message);
}
const shipmentId = response.data.Shipments[0].ID;
return {
success: true,
shipmentId: shipmentId,
data: response.data,
message: 'Shipment created successfully'
};
} catch (error) {
console.error('Error creating shipment:', error.message);
return {
success: false,
error: 'Failed to create shipment',
details: error.message
};
}
}
Creating the Shipment Controller
Create src/controllers/shipmentController.js
:
const AramexService = require('../services/aramexService');
class ShipmentController {
constructor() {
this.aramexService = new AramexService();
}
// Get list of available cities
async getCities(req, res) {
try {
const result = await this.aramexService.getCityList();
if (result.success) {
res.status(200).json({
success: true,
cities: result.data
});
} else {
res.status(400).json({
success: false,
message: result.error,
details: result.details
});
}
} catch (error) {
res.status(500).json({
success: false,
message: 'Internal server error',
details: error.message
});
}
}
// Calculate shipping rate
async calculateRate(req, res) {
try {
const {
originCity,
destinationCity,
weight,
dimensions,
codAmount
} = req.body;
// Validate required fields
if (!originCity || !destinationCity || !weight) {
return res.status(400).json({
success: false,
message: 'Origin city, destination city, and weight are required'
});
}
const originAddress = {
Line1: 'Origin Address',
City: originCity,
PostCode: '00000',
CountryCode: process.env.ARAMEX_ACCOUNTCOUNTRYCODE
};
const destinationAddress = {
Line1: 'Destination Address',
City: destinationCity,
PostCode: '00000',
CountryCode: process.env.ARAMEX_ACCOUNTCOUNTRYCODE
};
const shipmentDetails = {
PaymentType: codAmount ? 'C' : 'P',
ProductGroup: 'DOM',
ProductType: 'SMP',
ActualWeight: { Unit: 'KG', Value: weight },
NumberOfPieces: 1,
GoodsDescription: 'General Merchandise',
Services: codAmount ? 'CODS' : '',
Dimensions: dimensions || {
Length: 10, Width: 10, Height: 10, Unit: 'CM'
},
CashOnDeliveryAmount: codAmount ? {
CurrencyCode: 'NPR',
Value: codAmount
} : null
};
const result = await this.aramexService.calculateRate(
originAddress,
destinationAddress,
shipmentDetails
);
if (result.success) {
res.status(200).json({
success: true,
rateDetails: result.data
});
} else {
res.status(400).json({
success: false,
message: result.error,
details: result.details
});
}
} catch (error) {
res.status(500).json({
success: false,
message: 'Internal server error',
details: error.message
});
}
}
// Create a new shipment
async createShipment(req, res) {
try {
const orderData = req.body;
// Validate required fields
const requiredFields = ['customerName', 'customerAddress', 'customerMobile', 'city'];
const missingFields = requiredFields.filter(field => !orderData[field]);
if (missingFields.length > 0) {
return res.status(400).json({
success: false,
message: 'Missing required fields',
missingFields: missingFields
});
}
const result = await this.aramexService.createShipment(orderData);
if (result.success) {
res.status(201).json({
success: true,
shipmentId: result.shipmentId,
message: result.message,
data: result.data
});
} else {
res.status(400).json({
success: false,
message: result.error,
details: result.details
});
}
} catch (error) {
res.status(500).json({
success: false,
message: 'Internal server error',
details: error.message
});
}
}
}
module.exports = new ShipmentController();
Implementing Order Tracking
Creating the Tracking Service
Create src/services/trackingService.js
:
const axios = require('axios');
require('dotenv').config();
class TrackingService {
constructor() {
this.username = process.env.ARAMEX_USERNAME;
this.password = process.env.ARAMEX_PASSWORD;
this.accountNumber = process.env.ARAMEX_ACCOUNTNUMBER;
this.accountPin = process.env.ARAMEX_ACCOUNTPIN;
this.accountEntity = process.env.ARAMEX_ACCOUNTENTITY;
this.accountCountryCode = process.env.ARAMEX_ACCOUNTCOUNTRYCODE;
this.trackingUrl = process.env.ARAMEX_TRACKING_URL;
}
// Get client information for tracking requests
getClientInfo() {
return {
UserName: this.username,
Password: this.password,
Version: 'v1',
AccountNumber: this.accountNumber,
AccountPin: this.accountPin,
AccountEntity: this.accountEntity,
AccountCountryCode: this.accountCountryCode,
Source: 24
};
}
// Track single shipment
async trackShipment(trackingNumber) {
try {
if (!trackingNumber) {
throw new Error('Tracking number is required');
}
const url = `${this.trackingUrl}/Service_1_0.svc/json/TrackShipments`;
const payload = {
ClientInfo: this.getClientInfo(),
Shipments: [trackingNumber.toString()]
};
const response = await axios.post(url, payload, {
headers: { 'Content-Type': 'application/json' }
});
if (response.data.HasErrors) {
throw new Error(response.data.Notifications[0].Message);
}
const trackingResults = response.data.TrackingResults;
if (!trackingResults || trackingResults.length === 0) {
return {
success: false,
message: 'No tracking information found for this shipment'
};
}
const trackingData = trackingResults[0];
return {
success: true,
trackingNumber: trackingNumber,
trackingData: trackingData,
lastUpdate: new Date().toISOString()
};
} catch (error) {
console.error('Error tracking shipment:', error.message);
return {
success: false,
error: 'Failed to track shipment',
details: error.message
};
}
}
// Track multiple shipments
async trackMultipleShipments(trackingNumbers) {
try {
if (!Array.isArray(trackingNumbers) || trackingNumbers.length === 0) {
throw new Error('Array of tracking numbers is required');
}
const url = `${this.trackingUrl}/Service_1_0.svc/json/TrackShipments`;
const payload = {
ClientInfo: this.getClientInfo(),
Shipments: trackingNumbers.map(num => num.toString())
};
const response = await axios.post(url, payload, {
headers: { 'Content-Type': 'application/json' }
});
if (response.data.HasErrors) {
throw new Error(response.data.Notifications[0].Message);
}
const trackingResults = response.data.TrackingResults || [];
return {
success: true,
trackingResults: trackingResults,
totalShipments: trackingNumbers.length,
lastUpdate: new Date().toISOString()
};
} catch (error) {
console.error('Error tracking multiple shipments:', error.message);
return {
success: false,
error: 'Failed to track shipments',
details: error.message
};
}
}
// Get shipment status summary
getShipmentStatus(trackingData) {
if (!trackingData || !trackingData.Value) {
return 'Unknown';
}
const updatesList = trackingData.Value.UpdatesList;
if (!updatesList || updatesList.length === 0) {
return 'No updates available';
}
// Get the latest update
const latestUpdate = updatesList[updatesList.length - 1];
return latestUpdate.UpdateDescription || 'Status update available';
}
}
module.exports = TrackingService;
Creating the Tracking Controller
Create src/controllers/trackingController.js
:
const TrackingService = require('../services/trackingService');
class TrackingController {
constructor() {
this.trackingService = new TrackingService();
}
// Track single shipment
async trackShipment(req, res) {
try {
const { trackingNumber } = req.params;
if (!trackingNumber) {
return res.status(400).json({
success: false,
message: 'Tracking number is required'
});
}
const result = await this.trackingService.trackShipment(trackingNumber);
if (result.success) {
const status = this.trackingService.getShipmentStatus(result.trackingData);
res.status(200).json({
success: true,
trackingNumber: result.trackingNumber,
status: status,
trackingDetails: result.trackingData,
lastUpdate: result.lastUpdate
});
} else {
res.status(404).json({
success: false,
message: result.error || result.message,
details: result.details
});
}
} catch (error) {
res.status(500).json({
success: false,
message: 'Internal server error',
details: error.message
});
}
}
// Track multiple shipments
async trackMultipleShipments(req, res) {
try {
const { trackingNumbers } = req.body;
if (!Array.isArray(trackingNumbers) || trackingNumbers.length === 0) {
return res.status(400).json({
success: false,
message: 'Array of tracking numbers is required'
});
}
if (trackingNumbers.length > 50) {
return res.status(400).json({
success: false,
message: 'Maximum 50 tracking numbers allowed per request'
});
}
const result = await this.trackingService.trackMultipleShipments(trackingNumbers);
if (result.success) {
const processedResults = result.trackingResults.map(trackingData => ({
trackingNumber: trackingData.Key,
status: this.trackingService.getShipmentStatus(trackingData),
trackingDetails: trackingData
}));
res.status(200).json({
success: true,
totalShipments: result.totalShipments,
results: processedResults,
lastUpdate: result.lastUpdate
});
} else {
res.status(400).json({
success: false,
message: result.error,
details: result.details
});
}
} catch (error) {
res.status(500).json({
success: false,
message: 'Internal server error',
details: error.message
});
}
}
// Get shipment status only
async getShipmentStatus(req, res) {
try {
const { trackingNumber } = req.params;
const result = await this.trackingService.trackShipment(trackingNumber);
if (result.success) {
const status = this.trackingService.getShipmentStatus(result.trackingData);
res.status(200).json({
success: true,
trackingNumber: result.trackingNumber,
status: status,
lastUpdate: result.lastUpdate
});
} else {
res.status(404).json({
success: false,
message: result.error || result.message
});
}
} catch (error) {
res.status(500).json({
success: false,
message: 'Internal server error',
details: error.message
});
}
}
}
module.exports = new TrackingController();
Setting Up Express Application
Create src/app.js
:
const express = require('express');
const bodyParser = require('body-parser');
require('dotenv').config();
// Import controllers
const shipmentController = require('./controllers/shipmentController');
const trackingController = require('./controllers/trackingController');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// CORS middleware for development
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
// Health check endpoint
app.get('/health', (req, res) => {
res.status(200).json({
success: true,
message: 'Aramex API service is running',
timestamp: new Date().toISOString()
});
});
// Shipment routes
app.get('/api/cities', shipmentController.getCities.bind(shipmentController));
app.post('/api/calculate-rate', shipmentController.calculateRate.bind(shipmentController));
app.post('/api/create-shipment', shipmentController.createShipment.bind(shipmentController));
// Tracking routes
app.get('/api/track/:trackingNumber', trackingController.trackShipment.bind(trackingController));
app.post('/api/track-multiple', trackingController.trackMultipleShipments.bind(trackingController));
app.get('/api/status/:trackingNumber', trackingController.getShipmentStatus.bind(trackingController));
// Error handling middleware
app.use((err, req, res, next) => {
console.error('Unhandled error:', err);
res.status(500).json({
success: false,
message: 'Internal server error',
details: process.env.NODE_ENV === 'development' ? err.message : 'Something went wrong'
});
});
// 404 handler
app.use('*', (req, res) => {
res.status(404).json({
success: false,
message: 'Endpoint not found'
});
});
// Start server
app.listen(PORT, () => {
console.log(`🚀 Aramex API service is running on port ${PORT}`);
console.log(`📍 Health check: http://localhost:${PORT}/health`);
console.log(`📋 API Documentation:`);
console.log(` GET /api/cities - Get available cities`);
console.log(` POST /api/calculate-rate - Calculate shipping rate`);
console.log(` POST /api/create-shipment - Create new shipment`);
console.log(` GET /api/track/:trackingNumber - Track shipment`);
console.log(` POST /api/track-multiple - Track multiple shipments`);
console.log(` GET /api/status/:trackingNumber - Get shipment status`);
});
module.exports = app;
Conclusion
This comprehensive guide has walked you through implementing the Aramex API in a Node.js application, covering everything from basic setup to advanced features. You now have a solid foundation for integrating Aramex shipping services into your applications.
Key Takeaways
- Proper Setup: Always ensure your environment variables are correctly configured
- Error Handling: Implement robust error handling for all API interactions
- Input Validation: Validate all input data before sending to the API
- Monitoring: Implement logging and monitoring for production deployments
Next Steps
To further enhance your implementation, consider:
- Database Integration: Store shipment and tracking data in a database
- User Interface: Build a web interface for managing shipments
- Notification System: Implement email/SMS notifications for status updates
- Analytics: Add tracking and analytics for shipment performance
- Multi-carrier Support: Extend to support multiple shipping carriers
The Aramex API offers powerful capabilities for e-commerce and logistics applications. With this implementation guide, you’re well-equipped to build robust shipping solutions that can scale with your business needs.
Remember to always refer to the official Aramex API documentation for the latest updates and features, and ensure your implementation complies with their terms of service and rate limits.
Happy coding!