EasyParcel API Documentation
Welcome to the EasyParcel API Documentation! This guide will help you integrate with EasyParcel and get access to shipping functionalities via a RESTful API interface.
Overview
The EasyParcel API enables you to manage shipping, obtain quotations, track shipments, and much more. It's designed using a RESTful architecture, offering a seamless integration with various e-commerce platforms and third-party applications.
Key Benefits:
- Rate Calculation: Get live rates from various couriers.
- Order Management: Create, update, and manage shipments.
- Tracking: Real-time tracking updates for shipments.
- Effortless APP Integrate: Easy integration with your online store or application.
Setup Flow
Below is a visual guide to set up flow:
Getting Started
To begin using the EasyParcel API, follow the steps below to set up your environment:
Once set up, you can use the provided Sandbox environment to test the API without impacting live data.
OAuth Authentication
EasyParcel uses OAuth 2.0 for secure authentication, enabling controlled access to the system.
OAuth 2.0 Overview:
- OAuth 2.0 is a standard authorization framework allowing third-party applications to access your EasyParcel resources without exposing sensitive credentials.
Steps to Obtain OAuth Token:
API Functions & Feature
The EasyParcel API offers a wide array of functionalities divided into categories. Below are the key features available:
Standard Features:
Get Shipment Quotation
Get a detailed quote for your shipment, including rates, delivery times, and courier options.
Read moreGet Coupon List
Fetch all available courier according to the country. Read moreSubmit Shipment Orders
Create and submit shipment orders for processing.
Read more
OnDemand Features:
Get OnDemand Quotation
Get an on-demand quotation based on specific criteria.
Read moreSubmit OnDemand Order
Create an on-demand shipment order.
Read more
Wallet Features:
- Get Wallet Balance
Check your current wallet balance for API transactions.
Read more
Contact Us
If you have any questions or need further support with the EasyParcel API, our team is available for assistance. You can reach out to us via the following channels:
- WhatsApp Support: For quick support, chat with our team directly on WhatsApp. Click here to start a conversation.
We’re here to help you integrate and make the most out of EasyParcel’s services!
Developer Hub
Welcome to the EasyParcel Developer Hub
The EasyParcel Developer Hub is your one-stop destination for building and integrating custom shipping solutions using our API.
Why Register on the Developer Hub?
The EasyParcel Developer Hub is the central portal for developers who want to integrate with our API. Registration is required to:
- Create and manage OAuth applications
- Generate authentication credentials (client ID and client secret)
- Access API documentation and resources
- Test API endpoints in a sandbox environment
- Monitor API usage and performance
What You Can Do Here
- Create and manage your apps to access EasyParcel's APIs securely.
- Integrate with our Open API for features like quotations, order submissions, and tracking.
- Subscribe to Webhooks to receive real-time shipment updates.
- Test with a Sandbox Account that includes free test credit and no impact on your live data.
Whether you're developing a plugin, connecting your e-commerce store, or building a custom logistics tool — the Developer Hub has everything you need to get started.
Registering on the EasyParcel Developer Hub
This guide provides step-by-step instructions for registering on the EasyParcel Developer Hub and setting up your application to access the EasyParcel API.
Registration Process
Step 1: Create a Developer Account
1.) Visit the EasyParcel Developer Hub and login
2.) Login or sign up easyparcel developer account.
You already singed up, you may proceed to login (skipped to step 2)
Click on the Sign Up
3.) Complete the registration form:
- Full name
- Email address
- Password (must be at least 8 characters with numbers and special characters)
- Company name
- Contact number
4.) Accept the Terms of Service and Privacy Policy
5.) Click Create Account
6.) Verify your email address by clicking the link sent to your email
Step 2: Complete Your Developer Profile
After verifying your email and logging in, you'll need to complete your developer profile with the following information:
Basic Information
- Account Name - Your developer account name (usually your company name)
- Website - Your company or personal website URL
Contact Information
EasyParcel will use this information to contact you about your account.
- Contact Email - Primary email for account communications
- Phone Number - Contact phone with country code
- Address 1* - Primary address
- Address 2 - Additional address information (optional)
- City* - Your city
- ZIP / Postal Code* - Your postal code
- State / Territory - Your state or territory
- Country - Your country
Emergency Developer Contact Information
These details are used to communicate critical technical information to developers who maintain apps.
- Emergency Developer Email* - Email for urgent technical communications
- Emergency Developer Phone Number* - Phone for urgent technical communications
Fields marked with an asterisk (*) are required.
Once you've filled out all required fields, click Save Profile to continue.
If you encounter any issues during registration or application setup, contact our developer support team at api@easyparcel.com.
Creating Easyparcel Application
Create an Application
To access the API, you need to create an application:
1.) In the Developer Hub dashboard, click on Applications
2.) Click Create New Application
3.) Fill in the application details:
- Application name
- Redirect URI (for OAuth flows)
Understanding Redirect URI
The Redirect URI (also known as callback URL) is a crucial component of the OAuth 2.0 authentication flow. Here's what you need to know:
What is a Redirect URI? A redirect URI is the URL in your application where Easy Parcel will send users after they successfully authenticate. It's essentially the "return address" for the OAuth flow.
Why is it required?
Security: Ensures that authorization codes are only sent to pre-registered, trusted URLs
OAuth Compliance: Required by OAuth 2.0 specification to prevent authorization code interception attacks
User Experience: Provides a seamless flow back to your application after authentication
How to configure your Redirect URI:
For Web Applications:
https://yourdomain.com/auth/callback
https://yourapp.com/oauth/easyparcel/callback
For Local Development:
http://localhost:3000/auth/callback
http://127.0.0.1:8080/callback
For Mobile Applications:
yourapp://oauth/callback.com.yourcompany.yourapp://auth
Once Create the App
Access Token Expiry Configuration
Easy Parcel allows you to configure the expiry time for access tokens based on your application's security requirements and user experience needs.
What are Access Tokens? Access tokens are credentials that allow your application to access Easy Parcel's API on behalf of authenticated users. They have a limited lifespan for security purposes.
Why Configure Token Expiry?
Security: Shorter expiry times reduce the risk if tokens are compromised
User Experience: Longer expiry times reduce the frequency of re-authentication
Compliance: Meet your organization's security policies and regulations
How to Set Token Expiry:
- In your application settings, look for Access Token expiration
- Select your preferred expiry duration from the dropdown
- Consider your application type and security requirements
- Save the configuration
Best Practices by Application Type:
Web Applications:
Recommended: 1-4 hours
Rationale: Balance between security and user experience
Implementation: Use refresh tokens for seamless renewal
Mobile Applications:
Recommended: 24 hours to 7 days
Rationale: Reduces frequent login prompts on mobile devices
Implementation: Implement background token refresh
Server-to-Server Integrations:
Recommended: 1-24 hours
Rationale: Automated systems can handle frequent token refresh
Implementation: Automatic token renewal in your backend
Public/Kiosk Applications: - Recommended: 15-60 minutes
Rationale: Higher security risk in public environments
Implementation: Frequent re-authentication acceptable
Fill in the application details:
- description (optional)
- Application logo (optional)
Once completed, congratulations! You have create your first app in easyparcel account!
Get App Client Credentials
Step 3: Get Client credentials
1.) Get the client creditials for oauth authentication
- client id
- client secret
2.) Follow the Steps to get Oauth access token
Sandbox Account
The EasyParcel sandbox account is a test environment designed for developers and integrators to simulate real-world usage of EasyParcel's API features without affecting live production data.
Key Highlights
- Free to use: The sandbox environment and test credits are completely free.
- Safe testing: You can freely test all API operations (like quotations, order submission, cancellation, etc.) without risk to your live account.
- Test credits available: You can simulate order submissions with test credits.
- Live account unaffected: No changes or charges are applied to your actual EasyParcel account.
Use Cases
Ideal For
- Testing API integrations before go-live
- QA and staging environments
- Training or demonstrations
For top up test credits instructions, please refer to the Top up Sandbox Credit guide.
Sandbox Limitation: refer here for Sandbox Limitations
Demo Account Setup Guide
Prerequisites
- Existing EasyParcel developer account
- Completed API application registration
- Client ID credentials
Step-by-Step Demo Account Setup
1. Access Developer Portal
URL: https://api.easyparcel.com
2. Select Application
Action: Choose your registered application from the dashboard
3. Navigate to Connections
Location: Settings → Connection Management
4. Add New Connection
Required:
✅ Sandbox environment selection
✅ Connection name
5. Prompt to login
Required:
Login using developers account credentials
6. Allow access request
Required:
Allow the application request to access account credentials and permisions
7. Verify Successful Setup
Confirmation: Look for active status indicator
Top Up Demo Account
In the Application settings, connection list, select Top Up
Top up the desired amount
Top up successful
Sandbox Limitations
While the EasyParcel sandbox environment allows full API integration testing, there are several limitations compared to the live environment.
⚠️ Key Limitations
- Shipment status will not update
Any shipment created in the sandbox will remain static — it will not progress through actual delivery stages.
- No tracking notifications
Add-on features such as SMS, email, and WhatsApp tracking notifications will not be triggered or sent.
Use the sandbox for development and testing purposes. For real transactions and shipment tracking, switch to the production environment.
Oauth Authentications
EasyParcel's API uses the OAuth 2.0 authorization framework to ensure secure access to its services. OAuth 2.0 allows applications to authenticate and access the API on behalf of a user without directly exposing user credentials.
OAuth 2.0
- Grant Types Supported: Authorization Code, Client Credentials
OAuth (Open Authorization) is an open standard protocol that allows secure authorization in a simple and standardized way from web, mobile, and desktop applications. EasyParcel uses OAuth to enable applications to securely access resources on behalf of the user without exposing the user's credentials.
OAuth involves three main components:
Client: The application requesting access to the user's resources.
Resource Server: The server hosting the protected resources.
Authorization Server: The server responsible for authenticating the user and issuing access tokens.
Security Considerations
Ensure to use HTTPS to protect communication between clients and servers to prevent eavesdropping and man-in-the-middle attacks.
OAuth 2.0 Authorization Flow
Authorization Endpoint
The Authorization Endpoint is used by the client to obtain authorization from the resource owner via user-agent redirection.
Authorization Endpoint URL:
https://api.easyparcel.com/oauth/login
Token Endpoint
The Token Endpoint is used by the client to obtain an access token by presenting its authorization grant.
Token Endpoint URL:
https://api.easyparcel.com/oauth/token
Get OAuth Access token
1.) Pass the below params to the urls
https://api.easyparcel.com/oauth/login
Request:
| Requested Parameters | Type | Required | Details | Remarks |
|---|---|---|---|---|
| client_id | string | Yes | client_id of your application | - |
| redirect_uri | string | Yes | The URL to which the client was redirected from the authorization server. The url of your app to redirect to | - |
| state | string | Optional | Generate and pass a unique string that helps ensure the response comes from the same client request, preventing CSRF attacks. | - |
2.) Will be prompt to login (these below steps are to authorize linking the application to your easyparcel account)
Login to your easyparcel account
Select an account desire to link (You can select either Demo or live account)
If you have not yet setup demo account, you follow : To setup demo account
Allow access to Authorize link the account to with the application
3.) Respond param in redirect url
Sample redirect url respond:
https://your-callback-url/callback?code=(code that requires to regenerate access token)
- code(pass in get access token url)
- state (if got pass in auth url request)
| Responded Parameters | Type | Details | Remarks |
|---|---|---|---|
| code | string | The authorization code to pass to Oauth to get the access token. | - |
| state | string | A unique string that helps ensure the response comes from the same client request, preventing CSRF attacks. | - |
4.) Pass the below params to get access token url or refresh access token url
https://api.easyparcel.com/oauth/token
Request:
- grant_type = “authorization_code”
- redirect_uri
- code
- refresh_token (if want refresh access token)
- state (optional)
Header authorization - Basic [encoded base:64 format (app_client_id:app_secret)]
-> get the string for app_client_id and app_secret from developer hub
->
Encode both client_id and app_secret into 64 format
->
Use encoded value and pass back into Basic
| Requested Parameters | Type | Required | Details | Remarks |
|---|---|---|---|---|
| grant_type | string | Yes | The authorization_code to generate the access token. | default = authorization_code |
| redirect_uri | string | Yes | The URI to which the client was redirected from the authorization server. The URL of your app to redirect to. | - |
| code | string | Yes | The authorization code received from the OAuth flow that needs to be exchanged for an access token. | - |
| refresh_token | string | Optional (Required for refresh) | The token that requests to generate a new access token once the current token expires. | - |
| state | string | Optional | Request to check the state. A unique string that helps ensure the response comes from the same client request, preventing CSRF attacks. | - |
5.) then will respond back with the access_token
{
"token_type": "Bearer",
"expires_in": 36000,
"expires_at": "2024-12-12T13:03:23.013Z",
"access_token": "your access token",
"refresh_token": "Your refresh token",
"refresh_token_expires_in": 31557600,
"refresh_token_expires_at": "2025-12-12T09:03:23.013Z",
"app": {
"client_id": "your client-id",
"callbackUrls": [],
"redirectUris": [ "Your redirect uri"]
}
}
| Responded Parameters | Type | Details | Remarks |
|---|---|---|---|
| token_type | string | Token type | - |
| expires_in | int | The token life span in seconds | - |
| expires_at | date time | The Access token expiry date | - |
| access_token | string | The access token, required to access the API | - |
| refresh_token | string | The new Refresh token for the next refresh (Depends if requested on Oauth/token) | - |
| refresh_token_expires_in | int | The refresh token life span in seconds | - |
| refresh_token_expires_at | date time | The refresh token expiry date | - |
| app | array | informations regarding your applications | Refer to App |
App
| Responded Parameters | Type | Details | Remarks |
|---|---|---|---|
| client_id | string | Client ID of the application | - |
| callbackUrls | string | Destination that sends the user back after they have authenticated and granted access | - |
| redirectUris | string | Redirect destination for the user after the authorization process | - |
6.) Use the access token to call the API Endppoints
Postman Collection
Getting Started
Our Postman collection provides a convenient way to explore and test the EasyParcel API endpoints. Follow these steps to get up and running quickly.
This guide helps you get started with the EasyParcel API using Postman, providing instructions for importing, configuring, and using our Postman collection.
Importing the Collection
- Download the collection JSON file from over Here
- Open Postman
- Click Import in the top-left corner
- Choose the File tab and select the downloaded JSON file
- Click Import
Configuration
Enter this redirect/call URL to your app, if you intent to use for postman
https://oauth.pstmn.io/v1/callback
Before using the collection, you need to set up your environment variables:
- Create a new environment in Postman
- Add the following variables:
apiVersion- Set to2025-12clientId- Your EasyParcel OAuth client IDclientSecret- Your EasyParcel OAuth client secret
Authentication
The EasyParcel API uses OAuth 2.0 for authentication. The collection is pre-configured with the necessary OAuth settings:
- In Postman, open the collection and click on the Authorization tab
- Verify that the authorization type is set to OAuth 2.0
- Click on Get New Access Token and follow these steps:
- Grant Type: Authorization Code
- Auth URL: https://developer.easyparcel.com/oauth/login
- Access Token URL: https://api.easyparcel.com/oauth/token
- Client ID: Your EasyParcel client ID
- Client Secret: Your EasyParcel client secret
- Scope: (leave as is or use specific scopes if provided)
- Click Request Token
- Once you receive the token, click Use Token
The collection will automatically include the token in all requests.
Testing Your First Request
To verify your setup is working correctly:
- Select the Get Wallet Balance request
- Click Send
- You should receive a successful response with your wallet balance
Troubleshooting
If you encounter issues with the collection:
Authentication Errors
- Verify your OAuth credentials (client ID and secret) are correctly set in the environment
- Check that your OAuth token hasn't expired (tokens typically expire after a set time)
- Try requesting a new token if authentication fails
Request Failures
- Check the response body for specific error messages
- Verify all required fields are included in your request
- Ensure date formats follow YYYY-MM-DD pattern
Postman-specific Issues
- Ensure you're using the latest version of Postman
- Try resetting the environment variables
- Clear the cookies and cache in Postman settings
API Functions & Features
The EasyParcel API offers various functionalities grouped under different categories. Below is an overview of the key features:
Standard Shipping: - Scheduled Delivery
Cost-effective
Tracking Available
Suitable for high volume shipment
OnDemand Shipping:
Speed: providing same-day delivery.
Real-Time Tracking: You can track your parcel in real-time once the booking is made.
Flexibility: You can choose your preferred vehicle and schedule the pick-up time.
Cost-Efficiency: You only pay for the services you need.
Priority Handling: Parcels are prioritized, ensuring faster delivery compared to standard methods.
Wallet:
- All submission will be deducting from credit waller
Get Courier List:
- Getting all the courier listing available for a country
Get Coupon List:
- Getting coupon available for the order for both standard shipping and ondemand
EasyParcel API Structure Overview
This document provides a visual representation of the different flows and processes available through the EasyParcel API.
API Structure Diagram
Standard
OnDemand
Wallet
Courier List
Version (2025-12)
Here we will provide you with the latest version of the EasyParcel API, along with any important changes or updates.
Standard Shipping
Standard shipping provides scheduled delivery with cost-effective solutions for businesses with regular shipping needs. This service offers comprehensive tracking, multiple courier options, and flexible additional features.
Shipping Workflow
Standard Shipping Flow
├── Order Flow
│ ├── Get Quotation
│ ├── Get Coupon Listing
│ └── Submit Order
└── Management Flow
├── Get Shipment Listing
├── Get Shipment Details
└── Cancel Orders
Shipment Quotations
Get shipment quotations from all available courier companies on the EasyParcel platform. Provide sender and receiver addresses to receive pricing details, available services, and additional features.
Authentication (Standard Quotation)
To authorize, use this code:
curl "https://api.easyparcel.com/open_api/2025-12/shipment/quotations" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
const headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
};
$headers = [
'Authorization: Bearer YOUR_ACCESS_TOKEN',
'Content-Type: application/json'
];
headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
}
EasyParcel uses Oauth 2.0 to allow access to the API. You can register a new Oauth 2.0 access at our developer portal.
The API expects the Oauth 2.0 to be included in all API requests to the server in a header that looks like the following:
Authorization: Bearer YOUR_ACCESS_TOKEN
HTTP Request (Quotation)
POST https://api.easyparcel.com/open_api/2025-12/shipment/quotations
Quotation Request
Example Request:
{
"shipment": [
{
"sender": {
"postcode": "10150",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "11950",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value":50,
"weight": 1.5,
"width": 5,
"length": 5,
"height": 5
}
]
}
Sender Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string(10) | true | Sender's postcode |
| subdivision_code | string(35) | true | Sender's subdivision code (ISO 3166) |
| country | string(2) | true | Sender's country code |
Receiver Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string(10) | true | Receiver's postcode |
| subdivision_code | string(35) | true | Receiver's subdivision code (ISO 3166) |
| country | string(2) | true | Receiver's country code |
Parcel Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| weight | double(8,2) | true | Parcel weight in KG |
| width | double(8,2) | false | Parcel width in CM |
| height | double(8,2) | false | Parcel height in CM |
| length | double(8,2) | false | Parcel length in CM |
| parcel_value | double(8,2) | false | Parcel value in account currency |
Quotation Response
Example Response:
{
"status_code": 200,
"request_id": "1770285829860.591d8c4f-ca8d-4e8b-9871-28e86ae541d9",
"message": "1 request success, 0 request error.",
"data": [
{
"status": "success",
"input": {
"sender": {
"postcode": "10150",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "11950",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value": 50,
"weight": 1.5,
"width": 5,
"length": 5,
"height": 5
},
"quotations": [
{
"courier": {
"service_id": "EP-CS096",
"service_name": "Aramex (Pick Up)",
"courier_id": "EP-CR0AP",
"courier_name": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Aramex.jpg",
"delivery_duration": null,
"service_tag": [
{
"name": "Service Destinations",
"value": "Domestic"
},
{
"name": "Service Methods",
"value": "Pick Up from Door"
},
{
"name": "Service Methods",
"value": "Deliver to Door"
},
{
"name": "Tracking Quality",
"value": "Regular"
},
{
"name": "Supported AWB",
"value": "Supported AWB size: A6"
}
],
"is_pickup": true,
"is_dropoff": false
},
"pricing": {
"currency": "MYR",
"total_amount": "10.84",
"shipment_price": "9.80",
"shipment_tax": "0.59",
"total_features_price": "0.45",
"total_features_tax": "0.00"
},
"features": [
{
"cod": {
"available": true,
"min_cod_amount": "MYR10.00",
"max_cod_amount": "MYR1000.00",
"min_cod_charges": "MYR10.00",
"cod_charging_rate": "4.00%",
"charges_description": "4.00% of the parcel value or MYR10.00, whichever is higher"
}
},
{
"sms_tracking": {
"sms_price": "0.20",
"custom_sms_price": "0.05",
"remove_ep_branding_price": "0.05",
"sms_tax": "0.00",
"custom_sms_tax": "0.00",
"remove_ep_branding_tax": "0.00"
}
},
{
"email_tracking": {
"email_price": "0.05",
"custom_email_price": "0.05",
"remove_ep_branding_price": "0.05",
"email_tax": "0.00",
"custom_email_tax": "0.00",
"remove_ep_branding_tax": "0.00"
}
},
{
"whatsapp_tracking": {
"whatsapp_price": "0.20",
"whatsapp_tax": "0.00"
}
}
]
}
]
}
]
}
Quotation Response
| Parameter | Type | Description |
|---|---|---|
| status_code | integer | HTTP status code |
| message | string | Response message summary |
| data | array | Array containing quotation results |
Data Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Request status (success/error) |
| input | object | Echo of input parameters |
| quotations | array | Available courier quotations |
Quotation Object
Each quotation contains detailed information about available shipping options:
Courier Information
| Parameter | Type | Description |
|---|---|---|
| service_id | string | Unique service identifier |
| service_name | string | Human-readable service name |
| courier_id | string | Unique courier identifier |
| courier_name | string | Courier company name |
| courier_logo | string | URL to courier logo image |
| delivery_duration | string/null | Expected delivery time |
| service_tag | array | Service categorization tags |
| is_pickup | boolean | True if pickup service is provided |
| is_dropoff | boolean | True if dropoff service is provided |
Pricing Information
| Parameter | Type | Description |
|---|---|---|
| currency | string | Currency code (e.g., MYR, USD) |
| total_amount | string | Final total including all fees |
| shipment_price | string | Base shipping price |
| total_features_price | string | Additional features cost |
Service Tags
Service tags provide categorization for different shipping services:
| Tag Name | Possible Values | Description |
|---|---|---|
| Service Label | Standard, Economy, Priority, EXD | Service speed/tier |
| Service Destinations | International, Domestic | Geographic scope |
| Service Methods | Pick Up, Drop-Off | Collection method |
Available Features
The API returns various optional features that can be added to shipments:
Cash on Delivery (COD)
available: Whether COD is supportedmin_cod_amount/max_cod_amount: COD limitscharges_description: Additional fee information
Tracking Services
sms_tracking: SMS notification pricingemail_tracking: Email notification pricingwhatsapp_tracking: WhatsApp notification pricing
Branding Options
awb_branding: Custom branding on shipping labels- Includes banner and text customization pricing
International Shipping
ddp_charges: Delivered Duty Paid charges- Includes import taxes, duties, and handling fees
Code Examples
Select a language from the options on the right to switch between PHP, JavaScript, and Python examples.
async function getShippingQuotes(senderPostcode, receiverPostcode) {
const requestData = {
list: [{
sender: {
postcode: senderPostcode,
subdivision_code: "MY-07",
country: "MY"
},
receiver: {
postcode: receiverPostcode,
subdivision_code: "MY-07",
country: "MY"
},
weight: 1.5,
width: 5,
length: 5,
height: 5,
parcel_value: 50
}]
};
try {
const response = await fetch(
'https://api.easyparcel.com/open_api/2025-12/shipment/quotations',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(requestData)
}
);
const data = await response.json();
if (data.status_code === 200) {
const quotations = data.data[0].quotations;
// Sort by price (lowest first)
quotations.sort((a, b) =>
parseFloat(a.pricing.total_amount) - parseFloat(b.pricing.total_amount)
);
return quotations;
} else {
throw new Error(data.message);
}
} catch (error) {
console.error('Failed to fetch quotations:', error);
throw error;
}
}
<?php
function getShippingQuotes($senderPostcode, $receiverPostcode) {
$requestData = [
'list' => [[
'sender' => [
'postcode' => $senderPostcode,
'subdivision_code' => 'MY-07',
'country' => 'MY'
],
'receiver' => [
'postcode' => $receiverPostcode,
'subdivision_code' => 'MY-07',
'country' => 'MY'
],
'weight' => 1.5,
'width' => 5,
'length' => 5,
'height' => 5,
'parcel_value' => 50
]]
];
$ch = curl_init('https://api.easyparcel.com/open_api/2025-12/shipment/quotations');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('cURL error: ' . curl_error($ch));
}
curl_close($ch);
$data = json_decode($response, true);
if ($data['status_code'] === 200) {
$quotations = $data['data'][0]['quotations'];
// Sort by price (lowest first)
usort($quotations, function($a, $b) {
return floatval($a['pricing']['total_amount']) -
floatval($b['pricing']['total_amount']);
});
return $quotations;
} else {
throw new Exception($data['message']);
}
}
?>
import requests
import json
def get_shipping_quotes(sender_postcode, receiver_postcode):
"""Get shipping quotations for a parcel."""
request_data = {
"list": [{
"sender": {
"postcode": sender_postcode,
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": receiver_postcode,
"subdivision_code": "MY-07",
"country": "MY"
},
"weight": 1.5,
"width": 5,
"length": 5,
"height": 5,
"parcel_value": 50
}]
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
try:
response = requests.post(
'https://api.easyparcel.com/open_api/2025-12/shipment/quotations',
headers=headers,
data=json.dumps(request_data)
)
data = response.json()
if data['status_code'] == 200:
quotations = data['data'][0]['quotations']
# Sort by price (lowest first)
quotations.sort(key=lambda x: float(x['pricing']['total_amount']))
return quotations
else:
raise Exception(data['message'])
except requests.exceptions.RequestException as e:
raise Exception(f"API request failed: {str(e)}")
Error Handling
Error Response Example:
{
"status_code": 200,
"message": "0 requests success, 1 request error.",
"data": [
{
"status": "error",
"input": {
"sender": {
"postcode": "10150",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value": 50,
"weight": 1.5,
"width": 5,
"length": 5,
"height": 5
},
"errors": [
"The receiver postcode field is required "
]
}
]
}
The API uses conventional HTTP response codes to indicate success or failure. In addition, the response body contains detailed error information.
HTTP Status Codes
| Code | Meaning |
|---|---|
| 200 | OK -- Request successful (check individual data status) |
| 400 | Bad Request -- Invalid parameters |
| 401 | Unauthorized -- Invalid Oauth 2.0 access token |
| 404 | Not Found -- Endpoint not found |
| 429 | Too Many Requests -- Rate limit exceeded |
| 500 | Internal Server Error -- Server error |
Error Response Structure
| Parameter | Type | Description |
|---|---|---|
| status | string | Always "error" for failed requests |
| input | object | The input that caused the error |
| errors | array | List of specific error messages |
Best Practices for Shipping Quotation
Input Validation
Always validate input parameters before making API requests:
- Verify postcode formats for different countries
- Ensure weight and dimensions are positive numbers
- Check country and subdivision codes against ISO standards
Rate Limiting
The API implements rate limiting to ensure fair usage:
- Batch multiple shipment quotes in a single request when possible
- Implement exponential backoff for 429 responses
- Cache responses when appropriate to reduce API calls
User Experience
To provide the best user experience:
- Sort quotations by price (ascending) by default
- Display courier logos and service names clearly
- Show delivery duration when available
- Allow users to toggle optional features
- Highlight popular or recommended services
Coupon Feature
The coupon feature allows customers to search for available promo codes and apply them during the shipment order submission. This helps users enjoy discounted rates or special benefits based on current promotional campaigns.
Searching for Coupons
Customers can retrieve a list of available coupon codes using the following endpoint:
HTTP Request (Coupon)
GET https://api.easyparcel.com/open_api/2025-12/shipment/get_coupon_list
This will return a list of valid promo codes available to use for the shipment from the user’s account, based on factors such as delivery type, courier, or region.
Coupon Request
Submitting to the Coupon Listing Endpoint based on the submit shipment order endpoint request to get the available coupon for the shipment
Sample Coupon Listing Request:
{
"shipment": [
{
"reference": "order 1190",
"service_id": "EP-CS096",
"collection_date": "2025-05-19",
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"item": [
{
"content": "Electronics",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 2
}
],
"sender": {
"name": "John Doe",
"company": "ABC Corp",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"email": "test@easyparcel.com",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"postcode": "10150",
"city": "Lunas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"receiver": {
"name": "Jane Smith",
"company": "XYZ Inc",
"phone_number_country_code": "MY",
"phone_number": "1163042981",
"email": "test@easyparcel.com",
"address_1": "456 High St",
"address_2": "Floor 2",
"postcode": "11950",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"feature": {
"sms_tracking": true,
"email_tracking": true,
"whatsapp_tracking": true,
"awb_branding": false
}
}
]
}
Coupon Respond
Coupon Listing API - Response Parameters
Sample Respone for the courier listing
{
"status_code": 200,
"message": "4 coupon(s) available",
"data": {
"account_id": 438368,
"currency_code": "MYR",
"coupons": [
{
"coupon_code": "77f39c22-427a-44f1-8bff-e4f3752ba165",
"title": "Test Coupon 1",
"description": "Test ",
"discounted_amount": "5.01",
"discount_rate": "20.00%",
"valid_from_date": "2025-05-12 18:04:33",
"valid_to_date": "2025-12-14 18:04:33"
},
{
"coupon_code": "10101f8b-1dc5-49e0-b4d3-09c5deb76513",
"title": "Test Coupon",
"description": "Test ",
"discounted_amount": "2.34",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "dfa5109a-2f35-427e-8482-9b0ab65c323f",
"title": "Test Coupon",
"description": "Test ",
"discounted_amount": "2.10",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "ad205174-d93d-4d6a-a5cc-1e989b0292eb",
"title": "Test Coupon",
"description": "Test ",
"discounted_amount": "1.89",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
}
]
}
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| message | string | Description of the response message |
| data | object | Container for coupon and account details |
data Object
| Parameter | Type | Description |
|---|---|---|
| account_id | int | The EasyParcel account ID |
| currency_code | string | Currency in which the discount is offered (e.g., MYR) |
| coupons | array | List of coupon objects available for use |
coupon Object (Inside coupons array)
| Parameter | Type | Description |
|---|---|---|
| coupon_code | string | Unique identifier for the coupon |
| title | string | Title or name of the coupon campaign |
| description | string | Description or note about the coupon |
| discounted_amount | string | Discount value in currency terms |
| discount_rate | string | Discount in percentage (e.g., "10.00%") |
| valid_from_date | string | Start datetime of coupon validity (UTC format) |
| valid_to_date | string | End datetime of coupon validity (UTC format) |
Applying Coupons
During the order submission process (e.g., /shipment/submit or /ondemand/shipment/submit), customers can apply a valid coupon code by including it in the request body.
To apply coupon just adding the coupon_codes parameters to the request
Sample Field in submit orders:
{
"coupon_codes" :["77f39c22-427a-44f1-8bff-e4f3752ba165"],
"shipment": [
{
// as per the shipment details
}
]
}
If the coupon is valid and applicable, the discounted amount will be reflected in the final pricing.
Please ensure the coupon is valid and not expired before applying. For additional validation feedback, refer to the response message from the submission endpoint.
Submit Orders
This feature enables users to submit shipment orders. Users are required to fill in the necessary fields to access the shipping service.
HTTP Request (Submit)
POST https://api.easyparcel.com/shipment/submit_orders
Submit Order Request
Request Sample
{
"coupon_codes": [
"77f39c22-427a-44f1-8bff-e4f3752ba165"
],
"shipment": [
{
"reference": "order 1190",
"service_id": "EP-CS096",
"collection_date": "2025-05-19",
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"item": [
{
"content": "Electronics",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 2
}
],
"sender": {
"name": "John Doe",
"company": "ABC Corp",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"email": "test@easyparcel.com",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"postcode": "10150",
"city": "Lunas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"receiver": {
"name": "Jane Smith",
"company": "XYZ Inc",
"phone_number_country_code": "MY",
"phone_number": "1163042981",
"email": "test@easyparcel.com",
"address_1": "456 High St",
"address_2": "Floor 2",
"postcode": "11950",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"feature": {
"sms_tracking": true,
"email_tracking": true,
"whatsapp_tracking": true,
"awb_branding": false
}
},
{
"reference": "order 1191",
"service_id": "EP-CS09C",
"collection_date": "2025-05-19",
"weight": 1.5,
"height": 30,
"length": 40,
"width": 20,
"item": [
{
"content": "Electronics",
"weight": 1,
"height": 30,
"length": 40,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 10,
"length": 20,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1
}
],
"sender": {
"name": "John Doe",
"company": "ABC Corp",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"email": "test@easyparcel.com",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"postcode": "10150",
"city": "Lunas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"receiver": {
"name": "Jane Smith",
"company": "XYZ Inc",
"phone_number_country_code": "MY",
"phone_number": "1163042981",
"email": "test@easyparcel.com",
"address_1": "456 High St",
"address_2": "Floor 2",
"postcode": "11950",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"feature": {
"sms_tracking": false,
"email_tracking": true,
"whatsapp_tracking": true,
"awb_branding": false
}
}
]
}
Main Structure
| Parameter | Type | Required | Description |
|---|---|---|---|
| shipment | array | Yes | Array of shipment orders |
Shipment Object
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| reference | string | No | Reference of the parcel | |
| - | ||||
| service_id | string(10) | Yes | Service Identification number | - |
| collection_date | date | Yes | Date to collect the parcel | Format: YYYY-MM-DD |
| customer_reference_no | string | No | Customer reference number | - |
| weight | double(8,2) | Yes | Weight of the parcel | in KG |
| unit | string | No | Unit of measurement | - |
| height | double(8,2) | Yes | Height of the parcel | in CM |
| length | double(8,2) | Yes | Length of the parcel | in CM |
| width | double(8,2) | Yes | Width of the parcel | in CM |
| item | array | Yes | Items in the parcel | refer to item |
| sender | object | Yes | Origin of the parcel | refer to sender |
| receiver | object | Yes | Destination of the parcel | refer to receiver |
| feature | object | Yes | Additional service features | refer to feature |
Sender
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| name | string | Yes | Sender's Name | - |
| company | string | No | Sender's Company | - |
| phone_number_country_code | string | Yes | ISO 3166-1 Alpha-2 Country code of the Phone number | Example: "MY" |
| phone_number | string | Yes | Sender's phone number | - |
| alternate_phone_number_country_code | string | No | ISO Country code for alternate phone number | - |
| alternate_phone_number | string | No | Sender's alternate phone number | - |
| string | No | Sender's email | - | |
| address_1 | string | Yes | Sender's address | - |
| address_2 | string | No | Sender's address (continued) | - |
| postcode | string | Yes | Sender's postcode | - |
| city | string | Yes | Sender's city/town | - |
| subdivision_code | string | No | Sender's state/province code | Example: "MY-07" |
| country_code | string(2) | Yes | The origin country of the parcel | Example: "MY" |
| point_code | string | No | A unique identifier for sender location | - |
Receiver
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| name | string | Yes | Receiver's Name | - |
| company | string | No | Receiver's Company | - |
| phone_number_country_code | string | Yes | ISO 3166-1 Alpha-2 Country code of the Phone number | Example: "MY" |
| phone_number | string | Yes | Receiver's phone number | - |
| alternate_phone_number_country_code | string | No | Country code for alternate phone number | - |
| alternate_phone_number | string | No | Receiver's alternate phone number | - |
| string | No | Receiver's email | - | |
| address_1 | string | Yes | Receiver's address | - |
| address_2 | string | No | Receiver's address (continued) | - |
| postcode | string | Yes | Receiver's postcode | - |
| city | string | Yes | Receiver's city/town | - |
| subdivision_code | string | No | Receiver's state/province code | Example: "MY-07" |
| country_code | string(2) | Yes | The destination country of the parcel | Example: "MY" |
| point_code | string | No | A unique identifier for receiver location | - |
Feature
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| sms_tracking | boolean | No | Enable SMS tracking notifications | Default: false |
| email_tracking | boolean | No | Enable email tracking notifications | Default: false |
| whatsapp_tracking | boolean | No | Enable WhatsApp tracking notifications | Default: false |
| awb_branding | object | No | Airway bill branding | refer to awb_branding |
| cod | object | No | Cash on Delivery | refer to cod |
awb_branding
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| enable | boolean | Yes | To enable or disable Airways Bills Branding | - |
cod
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| cod_amount | double | Yes | Cash on Delivery amount | - |
| cod_currency_code | string | Yes | Currency code for COD transaction | Example: "MYR" |
Items
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| content | string | Yes | Description of the content | - |
| weight | double(8,2) | Yes | Weight of the item | in KG |
| height | double(8,2) | Yes | Height of the item | in CM |
| length | double(8,2) | Yes | Length of the item | in CM |
| width | double(8,2) | Yes | Width of the item | in CM |
| currency_code | string(3) | Yes | The currency code of the item value | Example: "MYR" |
| value | double(8,2) | Yes | Value of the item | - |
| quantity | int | Yes | The item quantity | - |
Sumbit Order Response
Successful Response Example
{
"status_code": 200,
"message": "2 requests success, 0 request error.",
"data": [
{
"order_details": {
"order_number": "EI-2602-4P2SK",
"account_id": 8583757
},
"pricing_breakdown": {
"currency_code": "MYR",
"total_order_amount": "23.67",
"total_paid_amount": "23.67",
"total_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"shipments": [
{
"status": "success",
"shipment_number": "ES-2602-4VW9E",
"courier_service": null,
"courier": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Aramex.jpg",
"awb_number": null,
"awb_url": "",
"awb_urls_by_format": {
"A4": "",
"A5": "",
"A6": ""
},
"tracking_url": null,
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"pricing_breakdown": {
"currency_code": "MYR",
"total_paid_amount": "10.25",
"shipment_price": "9.80",
"shipment_tax_amount": "0.00",
"total_features_price": "0.45",
"total_features_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas",
"subdivision_code": "MY-07",
"postcode": "10150",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1163042981",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"postcode": "11950",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 2
}
],
"features": {
"cod": null,
"insurance_purchase": [
{
"service_name": "Insure Plus",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
},
{
"service_name": "Basic Coverage",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
}
],
"privacy_masking": null,
"shipment_tracking_whatsapp": {
"message": "Hey there! Your order from John Doe is ready to be collected for delivery soon!\n\nTracking no: null",
"phone_country_code": "MY",
"phone_number": "1163042981",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_sms": {
"message": "Your order from John Doe is ready & trackable once courier scans in. Track at EasyParcel with [Placeholder Trackin..] -Powered by EasyParcel",
"phone_country_code": "MY",
"phone_number": "1163042981",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_email": {
"email": "test@easyparcel.com",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.05",
"tax_amount": "0.00"
},
"shipment_awb_branding": null
},
"reference": "order 1190"
},
{
"status": "success",
"shipment_number": "ES-2602-VC4KV",
"courier_service": null,
"courier": "DHL eCommerce",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/DHLeC.jpg",
"awb_number": "7028021894371796",
"awb_url": "https://app.easyparcel.com/portal/v2/public/label/ES-2602-VC4KV/3972206?format=A4",
"awb_urls_by_format": {
"A4": "https://app.easyparcel.com/portal/v2/public/label/ES-2602-VC4KV/3972206?format=A4",
"A5": "",
"A6": "https://app.easyparcel.com/portal/v2/public/label/ES-2602-VC4KV/3972206?format=A6"
},
"tracking_url": "https://app.easyparcel.com/tools/easytrack/details?courier=DHLeC&awb=7028021894371796",
"weight": 4,
"height": 30,
"length": 40,
"width": 20,
"pricing_breakdown": {
"currency_code": "MYR",
"total_paid_amount": "13.42",
"shipment_price": "13.02",
"shipment_tax_amount": "0.00",
"total_features_price": "0.40",
"total_features_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas",
"subdivision_code": "MY-07",
"postcode": "10150",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1163042981",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"postcode": "11950",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics",
"weight": 1,
"height": 30,
"length": 40,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 10,
"length": 20,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1
}
],
"features": {
"cod": null,
"insurance_purchase": [
{
"service_name": "Insure Plus",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
},
{
"service_name": "Basic Coverage",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
}
],
"privacy_masking": [
{
"masking_section": "Sender Details",
"currency_code": "MYR",
"charge_amount": "0.07",
"bundle_discounted_amount": "0.03",
"tax_amount": "0.00",
"total_charge_amount": "0.00"
},
{
"masking_section": "Parcel Details",
"currency_code": "MYR",
"charge_amount": "0.08",
"bundle_discounted_amount": "0.02",
"tax_amount": "0.00",
"total_charge_amount": "0.00"
}
],
"shipment_tracking_whatsapp": {
"message": "Hey there! Your order from [Sender's Name] is ready to be collected for delivery soon!\n\nTracking no: [Tracking No.]",
"phone_country_code": "MY",
"phone_number": "1163042981",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_sms": null,
"shipment_tracking_email": {
"email": "test@easyparcel.com",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.05",
"tax_amount": "0.00"
},
"shipment_awb_branding": null
},
"reference": "order 1191"
}
]
}
]
}
Successful Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of order results |
Order Details Object
| Parameter | Type | Description |
|---|---|---|
| order_details | object | Details about the order |
| pricing | object | Pricing information |
| shipments | array | Array of shipment details |
Order Details
| Parameter | Type | Description |
|---|---|---|
| order_number | string | Order number of the shipment batch |
| account_id | string | Account ID used for the shipment |
Pricing
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used for the shipment |
| total_amount | string | Total cost of all shipments |
| total_tax_amount | string | Total tax amount |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the shipment request |
| referencce | string | Reference of ther parcel |
| shipment_number | string | The unique number of the shipment |
| courier_service | string | Service type selected for shipment |
| courier | string | Name of the courier service |
| collection_date | string | Collection date of the parcel |
| awb_url | string | URL to access the airway bill |
| awb_number | string | The airway bill number |
| awb_urls_by_format | object | AWB label URLs by format (A4, A5, A6) |
| tracking_url | string | URL to track the parcel |
| weight | double | Weight of the shipment |
| height | double | Height of the shipment |
| length | double | Length of the shipment |
| width | double | Width of the shipment |
| pricing_breakdown | object | Detailed pricing breakdown |
| sender | object | Sender details |
| receiver | object | Receiver details |
| shipment_items | array | Items in the shipment |
| features | object | Enabled features details |
Pricing Breakdown
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used for the shipment |
| total_order_amount | string | Total cost of the shipment |
| shipment_price | string | Base price of the shipment |
| total_tax_amount | string | Tax amount |
| total_features_price | string | Total price for additional features |
| coupon_redeemed | string | Total amonut deducted using coupon_redeemed |
Features
| Parameter | Type | Description |
|---|---|---|
| cod | object | Cash on Delivery details (if enabled) |
| shipment_tracking_whatsapp | object | WhatsApp tracking details (if enabled) |
| shipment_tracking_sms | object | SMS tracking details (if enabled) |
| shipment_tracking_email | object | Email tracking details (if enabled) |
Error Response
For failed requests, the response includes error details:
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code indicating error |
| message | string | Error summary message |
| data | array | Array of shipment request details |
| errors | array | List of specific error messages |
Error Response Example
{
"status_code": 200,
"message": "1 request success, 1 request error.",
"data": [
{
"order_details": {
"order_number": "EI-2601-CS99V",
"account_id": 8583757
},
"pricing_breakdown": {
"currency_code": "MYR",
"total_order_amount": "12.55",
"total_paid_amount": "12.55",
"total_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"shipments": [
{
"status": "success",
"shipment_number": "ES-2601-U2W24",
"courier_service": null,
"courier": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Aramex.jpg",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"pricing_breakdown": {
"currency_code": "MYR",
"total_paid_amount": "12.55",
"shipment_price": "12.10",
"shipment_tax_amount": "0.00",
"total_features_price": "0.45",
"total_features_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas",
"subdivision_code": "MY-07",
"postcode": "10150",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1163042981",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"postcode": "11950",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 2
}
],
"features": {
"cod": null,
"insurance_purchase": [
{
"service_name": "Insure Plus",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
},
{
"service_name": "Basic Coverage",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
}
],
"shipment_tracking_whatsapp": {
"message": "Hey there! Your order from John Doe is ready to be collected for delivery soon!\n\nTracking no: null",
"phone_country_code": "+60",
"phone_number": "1126760658",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_sms": {
"message": "Your order from John Doe is ready & trackable once courier scans in. Track at EasyParcel with [Placeholder Trackin..] -Powered by EasyParcel",
"phone_country_code": "+60",
"phone_number": "1163042981",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_email": {
"email": "test@easyparcel.com",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.05",
"tax_amount": "0.00"
},
"shipment_awb_branding": null
}
},
{
"status": "error",
"collection_date": "",
"weight": "",
"height": "",
"length": "",
"width": "",
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "",
"subdivision_code": "",
"postcode": "10150",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1163642281",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "",
"subdivision_code": "",
"postcode": "",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics",
"weight": 0.5,
"height": 30,
"length": 40,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1,
"insurance_purchase": null
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 10,
"length": 20,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 2,
"insurance_purchase": null
}
],
"features": {
"cod": false,
"shipment_tracking_whatsapp": false,
"shipment_tracking_sms": false,
"shipment_tracking_email": false
},
"errors": [
"The receiver postcode field is required "
]
}
]
}
]
}
Shipment Listing
This endpoint allows users to retrieve a list of shipments with optional filtering parameters. Results are sorted by the latest shipments first.
HTTP Request (Listing)
POST https://api.easyparcel.com/open_api/2025-12/shipment/list
Pagination
This API uses cursor-based pagination with the before_shipment_number parameter. To retrieve the next page of results:
- Make your initial request with desired filters and
limit - Note the
shipment_numberof the last shipment in the response - Use that shipment number as
before_shipment_numberin your next request to get older shipments
Since results are sorted newest first, each subsequent request returns the next set of older shipments.
Request Sample
{
"limit": 3,
"before_shipment_number": "ES-2601-K8S32",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Note: You can submit a request without any filters, but the maximum limit is 250 shipments per API call. Results are sorted with the latest shipments first.
Main Structure
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| limit | int | No | Maximum number of results to return | Default: 10, Maximum: 250 |
| before_shipment_number | string | No | Get shipments before this shipment number | For pagination purposes |
| shipment_status_code | string | No | Filter by shipment status code | Example: "7" for "Schedule In Arrangement" |
| date_from | date | No | Start date for filtering shipments | Format: YYYY-MM-DD |
| date_to | date | No | End date for filtering shipments | Format: YYYY-MM-DD |
Returned Parameters
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"shipment_number": "ES-2504-X2KV5",
"awb_number": "960301021838937",
"awb_url": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/courier/consignment_note/49854776-1dda-4c4b-9bad-f66157e8f6b4.pdf",
"tracking_url": "https://app.easyparcel.com/tools/easytrack/details?courier=City-Link Express&awb=960301021838937",
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-30 00:00:00",
"courier": {
"service_type": "City-Link Express (Drop-Off)",
"courier_id": "EP-CR0D9",
"service_id": "EP-CS0D9",
"courier_name": "City-Link Express (M) Sdn. Bhd.",
"courier_short_name": "City-Link Express",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "Afiq",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"address1": "No 4",
"subdivision_code": "MY-02",
"postal_code": "06000",
"country": "MY"
},
"receiver_details": {
"name": "Afiq Receiver",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"subdivision_code": "MY-07",
"postal_code": "11900",
"country": "MY"
},
"pricing": {
"currency_code": "MYR",
"price": 5.65
}
},
{
"shipment_number": "ES-2504-2AE3R",
"awb_number": "960301021837659",
"awb_url": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/courier/consignment_note/17306a0f-f6e9-40ea-9957-c1d1e53d7692.pdf",
"tracking_url": "https://app.easyparcel.com/tools/easytrack/details?courier=City-Link Express&awb=960301021837659",
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-28 00:00:00",
"courier": {
"service_type": "City-Link Express (Drop-Off)",
"courier_id": "EP-CR0D9",
"service_id": "EP-CS0D9",
"courier_name": "City-Link Express (M) Sdn. Bhd.",
"courier_short_name": "City-Link Express",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "test afiq kedah",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"address1": "taman suria 5",
"subdivision_code": "MY-02",
"postal_code": "06000",
"country": "MY"
},
"receiver_details": {
"name": "Test afiq penang",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"subdivision_code": "MY-07",
"postal_code": "11900",
"country": "MY"
},
"pricing": {
"currency_code": "MYR",
"price": 5.65
}
},
{
"shipment_number": "ES-2504-QBURU",
"awb_number": "960301021837651",
"awb_url": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/courier/consignment_note/ca605e9f-5a24-47cb-a6cb-f1e9590de3d5.pdf",
"tracking_url": "https://app.easyparcel.com/tools/easytrack/details?courier=City-Link Express&awb=960301021837651",
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-29 00:00:00",
"courier": {
"service_type": "City-Link Express (Drop-Off)",
"courier_id": "EP-CR0D9",
"service_id": "EP-CS0D9",
"courier_name": "City-Link Express (M) Sdn. Bhd.",
"courier_short_name": "City-Link Express",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "test afiq kedah",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"address1": "taman suria 5",
"subdivision_code": "MY-02",
"postal_code": "06000",
"country": "MY"
},
"receiver_details": {
"name": "Test afiq penang",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"subdivision_code": "MY-07",
"postal_code": "11900",
"country": "MY"
},
"pricing": {
"currency_code": "MYR",
"price": 5.65
}
}
],
"pagination": {
"next_page_token": "eyJsYXN0X2lkIjoyNzE0MywiZmlsdGVycyI6eyJ0cmFja2luZ19zdGF0dXMiOiI3IiwiZGF0ZV9mcm9tIjoiMjAyNS0wNC0wMSAwMDowMDowMCIsImRhdGVfdG8iOiIyMDI1LTA0LTIzIDIzOjU5OjU5In19",
"next_shipment_number": "ES-2504-QBURU",
"has_more": true,
"limit": 3,
"filter_applied": {
"tracking_status": "7",
"date_from": "2025-04-01 00:00:00",
"date_to": "2025-04-23 23:59:59",
"tracking_status_code": "7"
}
}
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of shipment objects |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| shipment_number | string | Unique shipment identifier |
| awb | string | Airway bill number (null if not assigned) |
| shipment_status_code | int | Status code of the shipment |
| shipment_status | string | Human-readable shipment status |
| coll_date | string | Collection date and time |
| courier | object | Courier information |
| sender_details | object | Sender information |
| receiver_details | object | Receiver information |
| pricing | object | Pricing information |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| service_type | string | Type of courier service |
| courier_id | string | Unique identifier for the courier |
| service_id | string | Unique identifier for the service |
| courier_name | string | Full name of the courier company |
| courier_short_name | string | Short name of the courier company |
| courier_logo | string | URL to the courier logo image |
Sender Details Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the sender |
| string | Email address of the sender | |
| contact | string | Contact number with country code |
| alternative_contact | string/int | Alternative contact number (0 if none) |
| address1 | string | First line of the sender's address |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
Receiver Details Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the receiver |
| string | Email address of the receiver | |
| contact | string | Contact number with country code |
| alternative_contact | string/int | Alternative contact number (0 if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
Pricing Object
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency code for the price |
| price | double | Price of the shipment |
Common Status Code
| Status Code | Description |
|---|---|
| 200 | Successful request |
| 400 | Bad request (missing or invalid parameters) |
| 401 | Unauthorized (invalid authentication) |
| 404 | Not found (no shipments matching the criteria) |
| 500 | Server error |
Usage Notes (Listing)
- For pagination, use the
before_shipment_numberparameter with the last shipment number from the previous request. - Date filters (
date_fromanddate_to) filter by shipment collection date. - Results are always sorted by newest first.
- When no filters are applied, the API returns the most recent shipments up to the specified limit.
Shipment Details
This endpoint allows users to retrieve detailed information about a specific shipment using its shipment number.
HTTP Request (Detail)
POST https://api.easyparcel.com/open_api/2025-12/shipment/details
Shipment Details Request
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| shipment_number | string | Yes | Shipment number to query | Format: ES-YYMM-XXXXX |
Request Sample
{
"shipment_number": "ES-2601-K8S32"
}
Shipment Details Response
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"shipment_number": "ES-2601-K8S32",
"order_number": "EI-2601-U8FZW",
"shipment_details": {
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"parcels_value": "100",
"insurance_label": "basic",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"coll_date": "2025-05-19 00:00:00"
},
"parcel_content": [
{
"content": "Electronics",
"weight": "0.50000",
"height": 5,
"length": 5,
"width": 5,
"value": 50,
"currency_code": "MYR"
},
{
"content": "Electronics 2",
"weight": "0.50000",
"height": 5,
"length": 5,
"width": 5,
"value": 50,
"currency_code": "MYR"
}
],
"courier": {
"courier_name": "Aramex",
"service_id": "EP-CS0AP",
"courier_id": "EP-CR0AP",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/aramex.jpg",
"service_types": "Aramex (Pick Up)"
},
"sender": {
"name": "John Doe",
"company_name": "ABC Corp",
"email": "test@easyparcel.com",
"contact": "+601126760658",
"alternative_contact": null,
"subdivision_code": "MY-07",
"postal_code": "10150",
"country": "MY",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas"
},
"receiver": {
"name": "Jane Smith",
"company_name": "XYZ Inc",
"email": "test@easyparcel.com",
"contact": "+601163042981",
"alternative_contact": null,
"subdivision_code": "MY-07",
"postal_code": "11950",
"country": "MY",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas"
},
"pricing": {
"currency_code": "MYR",
"total_price": "0.00",
"shipment_price": "9.80",
"tax_price": "0.00",
"sms_notification": "0.00",
"email_notification": "0.00",
"whatsapp_notification": "0.00",
"awb_branding": null,
"insurance": null,
"ddp": null
}
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array containing the shipment details |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| shipment_number | string | Unique shipment identifier |
| order_number | string | Order number associated with shipment |
| shipment_details | object | Detailed shipment information |
| parcel_content | array | List of items in the shipment |
| courier | object | Courier service information |
| sender | object | Sender information |
| receiver | object | Receiver information |
| pricing | object | Detailed pricing breakdown |
Shipment Details Object
| Parameter | Type | Description |
|---|---|---|
| weight | double | Total weight of the shipment |
| height | double | Height of the shipment |
| length | double | Length of the shipment |
| width | double | Width of the shipment |
| shipment_status_code | int | Status code of the shipment |
| shipment_status | string | Human-readable shipment status |
| parcels_value | string | Total value of items in the shipment |
| insurance_label | string | Insurance information (null if not insured) |
| awb_number | string | Airway bill number (null if not assigned) |
| tracking_url | string | URL to track the shipment |
| awb_url | string | URL to access the airway bill |
| coll_date | string | Collection date and time |
Parcel Content Object
| Parameter | Type | Description |
|---|---|---|
| content | string | Description of the item |
| weight | string | Weight of the item |
| height | int | Height of the item |
| length | int | Length of the item |
| width | int | Width of the item |
| value | double | Monetary value of the item |
| currency_code | string | Currency code for the item value |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| courier_name | string | Full name of the courier company |
| service_id | string | Unique identifier for the service |
| courier_id | string | Unique identifier for the courier |
| courier_logo | string | URL to the courier logo image |
| service_types | string | Type of courier service |
Sender Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the sender |
| company_name | string | Company name of the sender |
| string | Email address of the sender | |
| contact | string | Contact number with country code |
| alternative_contact | string | Alternative contact number (null if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
| address1 | string | First line of the sender's address |
| address2 | string | Second line of the sender's address |
| city | string | City/town of the sender |
Receiver Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the receiver |
| company_name | string | Company name of the receiver |
| string | Email address of the receiver | |
| contact | string | Contact number with country code |
| alternative_contact | string | Alternative contact number (null if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
| address1 | string | First line of the receiver's address |
| address2 | string | Second line of the receiver's address |
| city | string | City/town of the receiver |
Pricing Object
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency code for all pricing |
| total_price | string | Total price of the shipment |
| shipment_price | string | Base shipping cost |
| tax_price | string | Tax amount |
| sms_notification | string | Price for SMS notification (null if not enabled) |
| email_notification | string | Price for email notification (null if not enabled) |
| whatsapp_notification | string | Price for WhatsApp notification (null if not enabled) |
| awb_branding | string | Price for AWB branding (null if not enabled) |
| insurance | string | Price for insurance (null if not purchased) |
| ddp | string | Delivered Duty Paid fee (null if not applicable) |
Error Response
If the shipment is not found or the request is invalid, the API will return an error response:
{
"status_code": 404,
"message": "No Order with shipment_number ES-2601-K8S3 found from this account",
"data": []
}
Usage Notes (Detail)
- This endpoint retrieves comprehensive information about a single shipment.
- The shipment number must be in the format ES-YYMM-XXXXX (e.g., ES-2504-3WYYP).
- Values for various fields like awb_number, insurance_label, etc. may be null if they aren't applicable to the shipment's current status.
- Pricing details provide a complete breakdown of all charges associated with the shipment.
- The tracking_url can be used to provide tracking information to customers.
Cancel Shipments
This endpoint allows users to cancel one or more shipments. Users can provide a list of shipment numbers along with cancellation remarks.
HTTP Request (Cancel)
POST https://api.easyparcel.com/open_api/2025-12/shipment/cancel
Cancel Request Parameters
Request Sample
{
"cancel_list": [
{
"shipment_number": "ES-2601-K8S32",
"remark": "test"
},
{
"shipment_number": "ES-2601-XV7UN",
"remark": "test"
}
]
}
Main Structure
| Parameter | Type | Required | Description |
|---|---|---|---|
| cancel_list | array | Yes | List of shipments to cancel |
Cancel Item Object
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| shipment_number | string | Yes | Shipment number to cancel | Format: ES-YYMM-XXXXX |
| remark | string | Yes | Reason for cancellation | - |
Cancel Return Parameters
Successful Response Example
{
"status_code": 200,
"message": "2 requests success, 0 request error.",
"data": [
{
"status": "success",
"message": "Shipment Cancelled",
"shipment_number": "ES-2602-4VW9E"
},
{
"status": "success",
"message": "Shipment Cancelled",
"shipment_number": "ES-2602-VC4KV"
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Summary message (e.g., "2 requests success, 0 request error.") |
| data | array | Array of cancellation results |
Cancellation Result Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the cancellation request ("success" or "error") |
| message | string | Detailed message about the cancellation result |
| shipment_number | string | The shipment number that was processed |
Error Response Example
{
"status_code": 200,
"message": "0 requests success, 3 request error.",
"data": [
{
"status": "error",
"message": "Shipment Already Cancelled, Cannot Cancel Again",
"shipment_number": "ES-2602-4VW9E"
},
{
"status": "error",
"message": "The shipment cancellation period is over (7 days from collection date: 2025-05-19)",
"shipment_number": "ES-2602-VC4KV"
},
{
"status": "error",
"message": "Shipment Not Found",
"shipment_number": "ES-2504-GPC39"
}
]
}
Usage Notes (Cancellation)
- You can cancel multiple shipments in a single request by including them in the
cancel_listarray. - Only shipments that have not yet been processed by the courier can be cancelled.
- Each shipment in the
cancel_listwill be processed independently - some may succeed while others fail. - A successful response (
status_code: 200) does not guarantee all shipments were cancelled. Always check individual status values in the data array. - Cancellation remarks are mandatory and should provide a reason for the cancellation.
- The API returns a 200 status code even when all cancellations fail, so always check the message and data fields.
Tracking Status Feature
The tracking status feature allows customers to retrieve real-time tracking information for their shipments using AWB (Air Waybill) numbers. This helps users monitor the delivery progress and current status of their parcels.
Retrieving Tracking Status
Customers can retrieve tracking information for one or multiple shipments using the following endpoint:
HTTP Request (Tracking Status)
POST https://api.easyparcel.com/open_api/2025-12/shipment/tracking_status
This endpoint returns detailed tracking information including the current status, historical events, and location data for each requested shipment.
Tracking Status Request
Submitting AWB Numbers to Get Tracking Information
You can submit multiple AWB numbers in a single request to retrieve tracking status for multiple shipments simultaneously.
Sample Tracking Status Request:
{
"awb_numbers": ["7028021894371796", "960301021838937", "960301021837659"]
}
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| awb_numbers | array | Yes | List of AWB numbers to track (max 100 per request) |
Tracking Status Response
Tracking Status API - Response Parameters
Sample Response for Tracking Status
{
"status_code": 200,
"message": "3 requests success, 0 request error.",
"data": {
"results": [
{
"status": "success",
"awb_number": "7028021894371796",
"shipment_number": "ES-2602-VC4KV",
"order_number": "EI-2602-4P2SK",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Schedule In Arrangement",
"latest_event_date": "2026-01-23T04:28:52.494Z",
"status_log": [
{
"event_date": "2026-01-23 12:29:47",
"shipment_status_code": 7,
"tracking_status": "Shipment data received - Awaiting Parcel Handover to DHL",
"location": "Kuala Lumpur Hub, Kuala Lumpur, MY"
},
{
"event_date": "2026-01-23 12:28:52",
"shipment_status_code": 7,
"tracking_status": "Data Submitted - Awaiting Parcel Handover to DHL",
"location": "BAYAN BARU, PENANG,, PIN, MY"
},
{
"event_date": "2026-01-23T04:28:52.494Z",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
}
]
},
{
"status": "success",
"awb_number": "960301021838937",
"shipment_number": "ES-2504-X2KV5",
"order_number": "EI-2504-SKMTH",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Schedule In Arrangement",
"latest_event_date": "2025-04-23 08:13:12",
"status_log": [
{
"event_date": "2025-04-23 16:13:00",
"shipment_status_code": 7,
"tracking_status": "Shipment information sent to City-Link",
"location": null
},
{
"event_date": "2025-04-23 08:13:12",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
}
]
},
{
"status": "success",
"awb_number": "960301021837659",
"shipment_number": "ES-2504-2AE3R",
"order_number": "EI-2504-WUHYR",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Shipment information sent to City-Link",
"latest_event_date": "2025-04-23 10:46:00",
"status_log": [
{
"event_date": "2025-04-23 02:46:36",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
},
{
"event_date": "2025-04-23 10:46:00",
"shipment_status_code": 7,
"tracking_status": "Shipment information sent to City-Link",
"location": null
}
]
}
]
}
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| request_id | string | Unique identifier for the API request |
| message | string | Summary of the response (e.g., number of successful/failed requests) |
| data | object | Container for tracking results |
data Object
| Parameter | Type | Description |
|---|---|---|
| results | array | List of tracking result objects for each AWB |
result Object (Inside results array)
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the tracking request ("success" or "not_found") |
| awb_number | string | Air Waybill number for the shipment |
| shipment_number | string | EasyParcel shipment reference number (only for successful requests) |
| order_number | string | EasyParcel order reference number (only for successful requests) |
| latest_shipment_status_code | int | Numeric code representing the current shipment status (only for successful requests) |
| latest_tracking_status | string | Human-readable description of the current status (only for successful requests) |
| latest_event_date | string | Date and time of the most recent tracking event (YYYY-MM-DD HH:MM:SS) (only for successful requests) |
| status_log | array | Chronological list of all tracking events for this shipment (only for successful requests) |
| message | string | Error message explaining why the request failed (only for failed requests) |
status_log Object (Inside status_log array)
| Parameter | Type | Description |
|---|---|---|
| event_date | string | Date and time when this event occurred (YYYY-MM-DD HH:MM:SS) |
| shipment_status_code | int | Numeric code representing the shipment status at this event |
| tracking_status | string | Human-readable description of the status at this event |
| location | string | Location where the event occurred (null if not available) |
Shipment Status Codes
Below are common shipment status codes you may encounter:
| Status Code | Description |
|---|---|
| 1 | Order Created |
| 2 | Payment Confirmed |
| 3 | Ready for Collection |
| 4 | Item Collected |
| 5 | In Transit to Hub |
| 6 | Processing at Hub |
| 7 | Schedule In Arrangement |
| 8 | Out for Delivery |
| 9 | Delivered |
| 10 | Delivery Failed |
| 11 | Return to Sender |
Note: Status codes may vary by courier and region. Refer to the API response for the most accurate status description.
Usage Notes (Tracking)
- Batch Tracking: You can track up to 100 AWB numbers in a single API request for efficiency.
- Real-time Updates: Tracking information is updated in near real-time as events are recorded by the courier.
- Status Log: The
status_logarray provides a complete history of all tracking events in chronological order. - Error Handling: If an AWB number is invalid or not found, the corresponding result object will have
status: "not_found"with a descriptive message field. - Date Format: All dates and times are returned in
YYYY-MM-DD HH:MM:SSformat in UTC timezone.
Example Use Cases
Single Shipment Tracking
{
"awb_numbers": ["7028021894371796"]
}
Multiple Shipment Tracking
{
"awb_numbers": [
"7028021894371796",
"960301021838937",
"960301021837659",
"1234567890"]
}
Error Response Example
If one or more AWB numbers are invalid:
{
"status_code": 200,
"request_id": "1769761472947.b7a9d539-083a-48d7-8974-0fd6f13baa72",
"message": "3 requests success, 1 request error.",
"data": {
"results": [
{
"status": "success",
"awb_number": "7028021894371796",
"shipment_number": "ES-2601-XV7UN",
"order_number": "EI-2601-U8FZW",
"latest_shipment_status_code": 8,
"latest_tracking_status": "Cancelled",
"latest_event_date": "2026-01-30 10:04:18",
"status_log": [
{
"event_date": "2026-01-23 12:29:47",
"shipment_status_code": 7,
"tracking_status": "Shipment data received - Awaiting Parcel Handover to DHL",
"location": "Kuala Lumpur Hub, Kuala Lumpur, MY"
},
{
"event_date": "2026-01-23 12:28:52",
"shipment_status_code": 7,
"tracking_status": "Data Submitted - Awaiting Parcel Handover to DHL",
"location": "BAYAN BARU, PENANG,, PIN, MY"
},
{
"event_date": "2026-01-23T04:28:52.494Z",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
},
{
"event_date": "2026-01-30 10:04:18",
"shipment_status_code": 8,
"tracking_status": "Cancelled",
"location": "Kuala Lumpur Hub, Kuala Lumpur, MY"
}
]
},
{
"status": "success",
"awb_number": "960301021838937",
"shipment_number": "ES-2504-X2KV5",
"order_number": "EI-2504-SKMTH",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Schedule In Arrangement",
"latest_event_date": "2025-04-23 08:13:12",
"status_log": [
{
"event_date": "2025-04-23 16:13:00",
"shipment_status_code": 7,
"tracking_status": "Shipment information sent to City-Link",
"location": null
},
{
"event_date": "2025-04-23 08:13:12",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
}
]
},
{
"status": "success",
"awb_number": "960301021837659",
"shipment_number": "ES-2504-2AE3R",
"order_number": "EI-2504-WUHYR",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Schedule In Arrangement",
"latest_event_date": "2025-04-23 02:46:36",
"status_log": [
{
"event_date": "2025-04-23 10:46:00",
"shipment_status_code": 7,
"tracking_status": "Shipment information sent to City-Link",
"location": null
},
{
"event_date": "2025-04-23 02:46:36",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
}
]
},
{
"awb_number": "1234567890",
"status": "not_found",
"message": "AWB number not found"
}
]
}
}
Insurance Quotation Feature
The insurance quotation feature allows customers to retrieve pricing information for shipment insurance coverage. This helps users understand the cost of insuring their valuable parcels and make informed decisions about protecting their shipments against loss or damage.
Retrieving Insurance Quotations
Customers can retrieve insurance pricing for one or multiple shipments using the following endpoint:
HTTP Request (Insurance Quotation)
POST https://api.easyparcel.com/open_api/2025-12/insurance_quotations
This endpoint returns detailed insurance pricing based on shipment details including courier, origin, destination, weight, and item values.
Insurance Quotation Request
Submitting Shipment Details to Get Insurance Pricing
You can submit multiple shipment scenarios in a single request to retrieve insurance quotations for batch processing.
Sample Insurance Quotation Request:
{
"list": [
{
"courier_id": "EP-CR0AP",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
{
"courier_id": "EP-CR0AW",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
}
]
}
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| list | array | Yes | Array of shipment objects to get insurance quotes for |
Shipment Object (Inside list array)
| Parameter | Type | Required | Description |
|---|---|---|---|
| courier_id | string | Yes | EasyParcel courier service ID (e.g., "EP-CR0AW") |
| currency_code | string | Yes | Currency code for the quotation (e.g., "MYR") |
| from_postcode | string | Yes | Origin postcode |
| from_country | string | Yes | Origin country code (ISO 3166-1 alpha-2, e.g., "MY") |
| to_postcode | string | Yes | Destination postcode |
| to_country | string | Yes | Destination country code (ISO 3166-1 alpha-2) |
| shipment_weight | number | Yes | Total shipment weight in kilograms |
| shipment_item | array | Yes | Array of item objects to be insured |
Item Object (Inside shipment_item array)
| Parameter | Type | Required | Description |
|---|---|---|---|
| value | number | Yes | Declared value of the item |
| quantity | int | Yes | Quantity of items |
| currency_code | string | Yes | Currency code for the item value (e.g., "MYR") |
Insurance Quotation Response
Insurance Quotation API - Response Parameters
Sample Response for Insurance Quotations
{
"status_code": 200,
"message": "2 requests success, 0 request error.",
"data": [
{
"status": "success",
"input": {
"courier_id": "EP-CR0AP",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
"insurance_quotations": [
{
"insurance_service_id": "EP-IR0D",
"insurance_service_name": "EasyCover",
"insurance_cover_notice": "for lost",
"currency_code": "MYR",
"charge_amount": 7.5,
"pricing": {
"currency_code": "MYR",
"charge_amount": 7.5,
"base_fee": 0,
"max_item_value": null,
"min_item_value": "200.01",
"percentage_rate": "0.025",
"max_item_value_coverage": 10000
}
}
]
},
{
"status": "success",
"input": {
"courier_id": "EP-CR0AW",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
"insurance_quotations": [
{
"insurance_service_id": "EP-IR0D",
"insurance_service_name": "EasyCover",
"insurance_cover_notice": "for lost",
"currency_code": "MYR",
"charge_amount": 75,
"pricing": {
"currency_code": "MYR",
"charge_amount": 75,
"base_fee": 0,
"max_item_value": null,
"min_item_value": "200.01",
"percentage_rate": "0.025",
"max_item_value_coverage": 10000
}
}
]
}
]
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| request_id | string | Unique identifier for the API request |
| message | string | Summary of the response (e.g., number of successful/failed requests) |
| data | array | Array of quotation result objects |
Quotation Result Object (Inside data array)
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the quotation request ("success" or "error") |
| input | object | Echo of the input parameters sent in the request |
| insurance_quotations | array | Array of available insurance options for this shipment |
Insurance Quotation Object (Inside insurance_quotations array)
| Parameter | Type | Description |
|---|---|---|
| insurance_service_id | string | Unique identifier for the insurance service |
| insurance_service_name | string | Display name of the insurance service (e.g., "EasyCover") |
| insurance_cover_notice | string | Coverage details or notice (e.g., "for lost") |
| currency_code | string | Currency code for the insurance charge |
| charge_amount | number | Total insurance charge amount |
| pricing | object | Detailed pricing breakdown for the insurance |
Pricing Object (Inside insurance_quotations)
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency code for pricing |
| charge_amount | number | Calculated insurance charge based on item value |
| base_fee | number | Base fee for insurance (if applicable) |
| max_item_value | number | Maximum item value for this pricing tier (null if no max) |
| min_item_value | string | Minimum item value required for this insurance tier |
| percentage_rate | string | Percentage rate applied to item value (e.g., "0.025" = 2.5%) |
| max_item_value_coverage | number | Maximum coverage amount available for items |
Understanding Insurance Pricing
Insurance charges are typically calculated based on:
- Base Fee: A flat fee that applies regardless of item value (if applicable)
- Percentage Rate: A percentage of the declared item value
- Value Tiers: Different rates may apply based on item value ranges
Example Calculation:
For an item valued at MYR 3,000: - Base Fee: MYR 0 - Percentage Rate: 2.5% (0.025) - Calculation: (3,000 × 0.025) + 0 = MYR 75
Usage Notes (Insurance Quotation)
- Batch Quotations: You can request insurance quotes for multiple shipments in a single API call for efficiency.
- Currency Consistency: Ensure the currency codes match across shipment items and quotation requests.
- Coverage Limits: Note the
max_item_value_coverageto understand the maximum insured amount available. - Minimum Values: Items below the
min_item_valuethreshold may not be eligible for insurance or may use different pricing. - Multiple Options: Some shipments may have multiple insurance service options available with different pricing structures.
Example Use Cases
Single Shipment Quotation
{
"list": [
{
"courier_id": "EP-CR0AP",
"currency_code": "MYR",
"from_postcode": "50000",
"from_country": "MY",
"to_postcode": "10450",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 1500,
"quantity": 1,
"currency_code": "MYR"
}
]
}
]
}
Multiple Items in One Shipment
{
"list": [
{
"courier_id": "EP-CR0AW",
"currency_code": "MYR",
"from_postcode": "11900",
"from_country": "MY",
"to_postcode": "11900",
"to_country": "MY",
"shipment_weight": 3,
"shipment_item": [
{
"value": 500,
"quantity": 2,
"currency_code": "MYR"
},
{
"value": 800,
"quantity": 1,
"currency_code": "MYR"
}
]
}
]
}
International Shipment
{
"list": [
{
"courier_id": "EP-CR0D9",
"currency_code": "MYR",
"from_postcode": "11900",
"from_country": "MY",
"to_postcode": "10001",
"to_country": "US",
"shipment_weight": 2,
"shipment_item": [
{
"value": 5000,
"quantity": 1,
"currency_code": "MYR"
}
]
}
]
}
Applying Insurance to Shipments
Once you receive an insurance quotation, you can apply the insurance to your shipment by including the insurance_service_id in your shipment submission request.
Example Insurance Application in Shipment Submission:
{
"shipment": [
{
"service_id": "EP-CS096",
"insurance_service_id": "EP-IR0D",
// ... other shipment details
}
]
}
Error Handling
If a quotation request fails, the response will include an error status:
{
"status_code": 200,
"message": "0 requests success, 2 request error.",
"data": [
{
"status": "error",
"input": {
"courier_id": "EP-CR0AP",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
"errors": [
"Insurance service not available for this request"
]
},
{
"status": "error",
"input": {
"courier_id": "",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
"errors": [
"The courier id field is required "
]
}
]
}
Couriers List
This endpoint allows users to retrieve a list of available courier services for a specific country.
HTTP Request (Courier List)
GET https://api.easyparcel.com/open_api/2025-12/courier/list
Courier List Request
Request Sample
{
"country_code": "MY"
}
Requested Parameters
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| country_code | string | Yes | Country code to filter by | Example: "MY" for Malaysia |
Courier List Response
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"courier_id": "EP-CR0AP",
"uuid": "01e1cad9-d20a-411f-8c71-a1b3ed722b3f",
"courier_name": "Aramex",
"short_name": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Aramex.jpg",
"country": "Malaysia"
},
{
"courier_id": "EP-CR0AW",
"uuid": "db129869-d2cd-474a-b3bf-9995a436ef85",
"courier_name": "DHL eCommerce",
"short_name": "DHLeC",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/DHLeC.jpg",
"country": "Malaysia"
},
{
"courier_id": "EP-CR0AM",
"uuid": "17bd49e0-f356-41d0-805e-2b6ee8e3d6cc",
"courier_name": "Poslaju National Courier",
"short_name": "Pos Laju",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Pos_Laju.jpg",
"country": "Malaysia"
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of available courier services |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| courier_id | string | Unique identifier for the courier |
| uuid | string | Universal unique identifier |
| courier_name | string | Full name of the courier company |
| short_name | string | Abbreviated name of the courier |
| courier_logo | string | URL to the courier's logo image |
| country | string | Country where the courier operates |
Error Response
If an invalid country code is provided, the API will return an error response:
{
"status_code": 400,
"message": "Invalid country code",
"data": []
}
Supported Country Codes
| Country Code | Country Name |
|---|---|
| MY | Malaysia |
| SG | Singapore |
Common Status Codes
| Status Code | Description |
|---|---|
| 200 | Successful request |
| 400 | Bad request (invalid country code) |
| 401 | Unauthorized (invalid authentication) |
| 500 | Server error |
Usage Notes (Courier List)
- The
courier_idvalue returned by this endpoint is used in other API calls, such as when submitting a shipment order. - Courier availability may vary by country. Use the appropriate country code to get relevant results.
- The response includes full company names and shortened display names for each courier.
- Courier logos can be used in your application to display carrier branding.
- There may be multiple entries for the same courier company if they offer different types of services.
Courier Drop-off Points Feature
The courier drop-off points feature allows customers to retrieve a list of available drop-off locations where they can physically bring their parcels for shipment. This helps users find convenient locations near them to drop off their packages instead of scheduling a pickup.
Retrieving Drop-off Points
Customers can retrieve a list of available drop-off locations for a specific courier using the following endpoint:
HTTP Request (Drop-off Points)
POST https://api.easyparcel.com/open_api/2025-12/courier/get_courier_dropoff_points
This endpoint returns detailed information about drop-off locations including addresses, operating hours, and contact information based on the specified courier and location parameters.
Drop-off Points Request
Submitting Location Details to Get Available Drop-off Points
You can query drop-off points by providing courier and location information to find the nearest available locations.
Sample Drop-off Points Request:
{
"courier_id": "EP-CR0AP",
"country_code": "MY",
"postcode": "10150",
"city": "Lunas",
"state_code": "MY-07"
}
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| courier_id | string | Yes | EasyParcel courier service ID (e.g., "EP-CR0A") |
| country_code | string | Yes | Country code (ISO 3166-1 alpha-2, e.g., "MY") |
| postcode | string | Yes | Postcode/ZIP code of the search location |
| city | string | Yes | City name for the search location |
| state_code | string | Yes | State/subdivision code (ISO 3166-2 format, e.g., "MY-02") |
Drop-off Points Response
Drop-off Points API - Response Parameters
Sample Response for Drop-off Points
{
"status_code": 200,
"message": "Success",
"data": [
{
"point_id": "EP-CB0FF",
"name": "Pejabat Pos Besar Pulau Pinang",
"address_1": "Tingkat Bawah, Bangunan Tuanku Syed Putra",
"address_2": "Leboh Downing",
"address_3": "",
"address_4": "",
"postcode": "10670",
"city": "Pulau Pinang",
"state": "png",
"phone_number": "04-2619222",
"info": "",
"image": "",
"start_time": "08:00:00",
"end_time": "13:00:00"
},
{
"point_id": "EP-CB0F9",
"name": "Pos Malaysia Ayer Itam",
"address_1": "JKR 19",
"address_2": "Jalan Paya Terubung",
"address_3": "",
"address_4": "",
"postcode": "11500",
"city": "Ayer Itam",
"state": "png",
"phone_number": "04-8283226",
"info": "",
"image": "",
"start_time": "08:00:00",
"end_time": "13:00:00"
},
{
"point_id": "EP-CB0F5",
"name": "Pos Malaysia Balik Pulau",
"address_1": "JKR 2312",
"address_2": "Jalan Besar",
"address_3": "",
"address_4": "",
"postcode": "11000",
"city": "Balik Pulau",
"state": "png",
"phone_number": "04-8668204",
"info": "",
"image": "",
"start_time": "08:00:00",
"end_time": "13:00:00"
},
{
"point_id": "EP-CB0FG",
"name": "Pos Malaysia Batu Ferringghi",
"address_1": "JKR 2340",
"address_2": "Jalan Batu Ferringghi",
"address_3": "",
"address_4": "",
"postcode": "11100",
"city": "Batu Ferringghi",
"state": "png",
"phone_number": "04-8668204",
"info": "",
"image": "",
"start_time": "08:00:00",
"end_time": "13:00:00"
}
]
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| request_id | string | Unique identifier for the API request |
| message | string | Description of the response status |
| data | array | Array of drop-off point objects |
Drop-off Point Object (Inside data array)
| Parameter | Type | Description |
|---|---|---|
| point_id | string | Unique identifier for the drop-off point |
| name | string | Name of the drop-off location |
| address_1 | string | Primary address line |
| address_2 | string | Secondary address line (street name, building details) |
| address_3 | string | Additional address line (may be empty) |
| address_4 | string | Additional address line (may be empty) |
| postcode | string | Postcode of the drop-off location |
| city | string | City where the drop-off point is located |
| state | string | State/region code or abbreviation |
| phone_number | string | Contact phone number for the drop-off location |
| info | string | Additional information or notes about the location (may be empty) |
| image | string | URL to an image of the location (may be empty) |
| start_time | string | Opening time in HH:MM:SS format (24-hour) |
| end_time | string | Closing time in HH:MM:SS format (24-hour) |
Understanding Operating Hours
Drop-off points have specific operating hours when customers can drop off their parcels:
- start_time: The time when the location opens for drop-offs
- end_time: The time when the location closes for drop-offs
- Format: Times are provided in 24-hour format (HH:MM:SS)
Example:
start_time: "08:00:00" → Opens at 8:00 AM
end_time: "13:00:00" → Closes at 1:00 PM
Important: Ensure customers arrive before the closing time to successfully drop off their parcels. Some locations may have limited operating hours (e.g., morning only).
Usage Notes (Courier List)
- Location-based Search: Results are typically sorted by proximity to the specified postcode and city.
- Courier-specific: Each courier may have different drop-off locations. Always query with the specific courier ID you're using.
- Operating Hours: Always check the
start_timeandend_timeto inform customers of available drop-off windows. - Empty Fields: Some fields like
address_3,address_4,info, andimagemay be empty strings if not applicable. - Phone Contact: The
phone_numbercan be used to verify operating hours or get additional information about the location.
Example Use Cases
Finding Drop-off Points in Kuala Lumpur
{
"courier_id": "EP-CR0AP",
"country_code": "MY",
"postcode": "50000",
"city": "Kuala Lumpur",
"state_code": "MY-14"
}
Finding Drop-off Points in Penang
{
"courier_id": "EP-CR0AP",
"country_code": "MY",
"postcode": "10000",
"city": "George Town",
"state_code": "MY-07"
}
Different Courier Service
{
"courier_id": "EP-CR0AW",
"country_code": "MY",
"postcode": "80000",
"city": "Johor Bahru",
"state_code": "MY-01"
}
Displaying Drop-off Points to Customers
When presenting drop-off points to your users, consider displaying:
- Location Name - Clear identification of the drop-off point
- Full Address - Concatenate address lines for easy navigation
- Operating Hours - Display in user-friendly format (e.g., "8:00 AM - 1:00 PM")
- Distance - Calculate and show distance from user's location (if possible)
- Contact Number - Allow users to call for inquiries
- Map Integration - Use address/postcode to show location on a map
Display Example:
📍 Pejabat Pos Besar Pulau Pinang
Tingkat Bawah, Bangunan Tuanku Syed Putra
Leboh Downing, 10670 Pulau Pinang
⏰ Operating Hours: 8:00 AM - 1:00 PM
📞 Phone: 04-2619222
Applying Drop-off Points to Shipments
Once a customer selects a drop-off point, you can include the point_id in your shipment submission request to indicate the parcel will be dropped off at that location instead of being picked up.
Example Drop-off Point Application in Shipment Submission:
{
"shipment": [
{
"service_id": "EP-CS096",
"dropoff_point_id": "EP-CB0FF",
"collection_method": "dropoff",
// ... other shipment details
}
]
}
Note: Specific implementation may vary based on the shipment submission endpoint requirements.
Error Handling
No Drop-off Points Available
If no drop-off points are found for the specified location:
{
"status_code": 200,
"message": "No drop-off points found",
"data": []
}
Invalid Courier or Location
If the courier ID is invalid or doesn't service the specified location:
{
"status_code": 400,
"message": "Invalid courier ID or location not serviced",
"data": null
}
State Codes Reference (Malaysia)
Common Malaysian state codes (ISO 3166-2):
| State Code | State Name |
|---|---|
| MY-01 | Johor |
| MY-02 | Kedah |
| MY-03 | Kelantan |
| MY-04 | Malacca (Melaka) |
| MY-05 | Negeri Sembilan |
| MY-06 | Pahang |
| MY-07 | Penang (Pulau Pinang) |
| MY-08 | Perak |
| MY-09 | Perlis |
| MY-10 | Selangor |
| MY-11 | Terengganu |
| MY-12 | Sabah |
| MY-13 | Sarawak |
| MY-14 | Kuala Lumpur |
| MY-15 | Labuan |
| MY-16 | Putrajaya |
Best Practices for Courier List
- Cache Results: Consider caching drop-off point data for a reasonable period (e.g., 24 hours) as locations rarely change frequently.
- Sort by Distance: If possible, calculate distance from user's location and sort results accordingly for better UX.
- Show Operating Hours Prominently: Make sure users are aware of the operating hours before traveling to a drop-off point.
- Provide Alternatives: If the nearest drop-off point is far, consider offering pickup service as an alternative.
- Verify Before Departure: Suggest users call the drop-off location to confirm operating hours, especially on public holidays.
- Map Integration: Integrate with mapping services (Google Maps, Waze) to provide navigation directions.
- Filter by Time: Allow users to filter drop-off points based on current time and whether they're currently open.
OnDemand Shipping
OnDemand API Flow Overview
This document provides a visual representation of the different flows and processes available through the EasyParcel API.
OnDemand Workflow Diagram
OnDemand Quotation
OnDemand Quotation Overview
This feature enables users to obtain on-demand shipment quotations from all courier companies available on the EasyParcel platform. Users need to provide sender and receiver addresses and waypoint information to retrieve shipment quotations. The response includes available courier services, transportation type, pricing details, and optional add-on features.
HTTP Request (OnDemand Quotation)
POST https://api.easyparcel.com/open_api/2025-12/ondemand/quotations
OnDemand Quotation Request Parameters
Request Sample
{
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"type": "pickup"
},
{
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia",
"type": "dropoff"
}
]
}
Main Structure
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| schedule_pickup_date | string | No | Scheduled pickup date (YYYY-MM-DD) | - |
| schedule_pickup_time | string | No | Scheduled pickup time (HH:MM:SS) | - |
| timezone | string | No | Pickup timezone | - |
| waypoint | array | Yes | List of pickup and dropoff points | Minimum 2 required |
| waypoint[*].coordinates.latitude | numeric | Yes | Location latitude | - |
| waypoint[*].coordinates.longitude | numeric | Yes | Location longitude | - |
| waypoint[*].address | string | No | Full address of the location | - |
| waypoint[*].type | string | Yes | Either pickup or dropoff |
- |
OnDemand Quotation Response Parameters
Sample Response
Refer to the full JSON response you provided in your message for all details on courier quotations including Lalamove and PandaGo examples with their respective vehicle types, prices, weight and dimension limits.
{
"status_code": 200,
"message": "",
"data": [
{
"status": "success",
"input": {
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"type": "pickup"
},
{
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia",
"type": "dropoff"
}
]
},
"quotations": [
{
"metadata": {
"quotationId": "3418817446335963964"
},
"courier": {
"service_id": "EP-CS0I",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Car",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "40kg",
"dimension": "50cmx50cmx50cm"
},
"pricing": {
"total_amount": 7.06,
"shipping_price": "7.06",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817446755394383"
},
"courier": {
"service_id": "EP-CS0F",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Bike",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "10kg",
"dimension": "30cmx30cmx30cm"
},
"pricing": {
"total_amount": 5.88,
"shipping_price": "5.88",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817660128027070"
},
"courier": {
"service_id": "EP-CS09",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "4X4",
"durations": "5mins",
"parcel_type_support": "Ideal for small fridge, washing machine, bike, 1-seater sofa",
"weight_limit": "250kg",
"dimension": "120cmx90cmx90cm"
},
"pricing": {
"total_amount": 27.06,
"shipping_price": "27.06",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817248574529909"
},
"courier": {
"service_id": "EP-CS05",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Large Van",
"durations": "5mins",
"parcel_type_support": "Ideal for washing machine, sofa, treadmill , large parcels",
"weight_limit": "800kg",
"dimension": "270cmx130cmx120cm"
},
"pricing": {
"total_amount": 57.65,
"shipping_price": "57.65",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817941557441277"
},
"courier": {
"service_id": "EP-CS0G",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Lorry 10-ft",
"durations": "5mins",
"parcel_type_support": "Ideal for queen size bed, fridge, 3-seater sofa, wardrobe",
"weight_limit": "1000kg",
"dimension": "290cmx150cmx150cm"
},
"pricing": {
"total_amount": 78.82,
"shipping_price": "78.82",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817672006300006"
},
"courier": {
"service_id": "EP-CS0M",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Lorry 14-ft",
"durations": "5mins",
"parcel_type_support": "Ideal for king size bed, large fridge, 3-seater sofa, wardro",
"weight_limit": "2500kg",
"dimension": "420cmx200cmx200cm"
},
"pricing": {
"total_amount": 125.29,
"shipping_price": "125.29",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817660128027086"
},
"courier": {
"service_id": "EP-CS0Y",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Van",
"durations": "5mins",
"parcel_type_support": "Ideal for small fridge, washing machine, bike, 1-seater sofa",
"weight_limit": "500kg",
"dimension": "170cmx100cmx120cm"
},
"pricing": {
"total_amount": 45.88,
"shipping_price": "45.88",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": null
},
"courier": {
"service_id": "EP-CS0R",
"courier_name": "PandaGo",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/pandaGo_pink.png"
},
"transport": {
"transportation_type": "Bike",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "15kg",
"dimension": "43cmx39cmx42cm"
},
"pricing": {
"total_amount": 7.06,
"shipping_price": "7.06",
"tax_amount": 0,
"currency": "MYR"
}
}
]
}
]
}
Main Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code |
| message | string | Status message |
| data | array | List of quotations with metadata |
Data Object Structure
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the request |
| input | object | Echo of submitted input |
| quotations | array | List of courier quotations |
Quotation Entry Structure
| Section | Parameter | Type | Description |
|---|---|---|---|
| metadata | quotationId | string | Unique quotation ID |
| courier | service_id | string | Service ID |
| courier_name | string | Courier name | |
| img_courier | string | Courier logo URL | |
| transport | transportation_type | string | Transport type (e.g., Bike, Car) |
| durations | string | Estimated delivery time | |
| parcel_type_support | string | Parcel suitability description | |
| weight_limit | string | Weight limit | |
| dimension | string | Max parcel dimension | |
| pricing | total_amount | string | Quotation price |
| currency | string | Currency (e.g., MYR) |
Sample Error Response
{
"status_code": 400,
"message": "Invalid input Error",
"data": [
"The waypoint 0 type field is required "
]
}
OnDemand Quotation Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (requests)
const requestData = {
schedule_pickup_date: "2025-05-19",
schedule_pickup_time: "11:48:35",
timezone: "Asia/Kuala_Lumpur",
waypoint: [
{ type: "pickup", coordinates: { latitude: 5.34, longitude: 100.28 } },
{ type: "dropoff", coordinates: { latitude: 5.32, longitude: 100.28 } }
]
};
fetch('https://api.easyparcel.com/open_api/2025-12/ondemand/quotations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(requestData)
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$data = [
"schedule_pickup_date" => "2025-05-19",
"schedule_pickup_time" => "11:48:35",
"timezone" => "Asia/Kuala_Lumpur",
"waypoint" => [
["type" => "pickup", "coordinates" => ["latitude" => 5.34, "longitude" => 100.28]],
["type" => "dropoff", "coordinates" => ["latitude" => 5.32, "longitude" => 100.28]]
]
];
$ch = curl_init('https://api.easyparcel.com/open_api/2025-12/ondemand/quotations');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = 'https://api.easyparcel.com/open_api/2025-12/ondemand/quotations'
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
data = {
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{"type": "pickup", "coordinates": {"latitude": 5.34, "longitude": 100.28}},
{"type": "dropoff", "coordinates": {"latitude": 5.32, "longitude": 100.28}}
]
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for OnDemand Quotation
- Input Validation – Validate all fields before API call.
- Sorting Quotations – Sort by total amount for better user experience.
- Optional Features – Allow users to toggle extras like insurance or SMS alerts.
- Display Info – Always show courier logos, transport type, and delivery time.
OnDemand Order Submission
This guide explains how to submit an on-demand shipment order with and without applying a coupon, and the structure of the response received.
HTTP Request (OnDemand Submit Order)
POST https://api.easyparcel.com/ondemand/order
OnDemand Submit Order Request
Request Sample
{
"coupon_codes":["ad205174-d93d-4d6a-a5cc-1e989b0292eb"],
"origin_country": "MY",
"ondemand_service_id": "EP-CS0I",
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3418817446335963964"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "127849162",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Asa",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oreo",
"email": "oreo@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| coupon_codes | string | Optional | Apply coupon codes to get further discount |
| ondemand_service_id | string | Yes | ID of the selected on-demand service |
| origin_country | string | Yes | ISO 3166-1 alpha-2 country code |
| schedule_pickup_date | string | Optional | Date of pickup (YYYY-MM-DD) |
| schedule_pickup_time | string | Optional | Time of pickup (HH:MM:SS) |
| time_zone | string | Optional | Time zone of the pickup schedule |
| metadata | object | Yes | Additional metadata, e.g. quotationId |
| waypoint | array | Yes | Array of pickup and dropoff points |
| waypoint[*].point | numeric | Yes | Sequence index (e.g., 0 = pickup, 1 = dropoff) |
| waypoint[*].type | string | Yes | Type of stop; must be "pickup" or "dropoff" |
| waypoint[*].coordinates.latitude | numeric | Yes | Latitude of the location |
| waypoint[*].coordinates.longitude | numeric | Yes | Longitude of the location |
| waypoint[*].item | array | Yes | Items associated with the waypoint |
| waypoint[].item[].quantity | string | Yes | Quantity of the item |
| waypoint[].item[].description | string | Optional | Description of the item |
| waypoint[].item[].dimensions.height | string | Yes | Height of the item (in cm) |
| waypoint[].item[].dimensions.width | string | Yes | Width of the item (in cm) |
| waypoint[].item[].dimensions.length | string | Yes | Length of the item (in cm) |
| waypoint[].item[].dimensions.weight | string | Yes | Weight of the item (in kg) |
| waypoint[*].shipment_info.name | string | Yes | Name of the sender/receiver |
| waypoint[*].shipment_info.email | string | Optional | Email address |
| waypoint[*].shipment_info.phone_number_country_code | string | Yes | Phone number country code (e.g., MY) |
| waypoint[*].shipment_info.phone_number | string | Yes | Phone number |
| waypoint[*].shipment_info.address | string | Yes | Full address |
| waypoint[*].remark | string | Optional | Any additional notes or instructions |
OnDemand Submit Order Response
Sample Response
{
"status_code": 200,
"message": "Success",
"data": {
"booking_id": "EOD-150",
"ondemand_service_id": "EP-CS0I",
"order_number": "3418823367426527326",
"tracking_url": "https://share.lalamove.com/?MY100260129095828875410020097479892&lang=en_MY&sign=a990c1f88bbbc8424c76a58174b5bad8&source=api_wrapper",
"courier": {
"service_id": 3,
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"pricing_breakdown": {
"currency_code": "MYR",
"total_order_amount": "7.06",
"total_paid_amount": "7.06",
"shipment_amount": "7.06",
"tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"shipment": {
"origin_country": "MY",
"ondemand_service_id": "EP-CS0I",
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3418817446335963964"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "127849162",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Asa",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oreo",
"email": "oreo@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
}
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code (e.g., 200) |
| message | string | Success or error message |
| data | object | Contains booking details and shipment info |
Data Object
| Parameter | Type | Description |
|---|---|---|
| booking_id | string | Booking ID for the on-demand shipment |
| ondemand_service_id | string | ID of the selected on-demand service |
| order_number | string | Unique order number |
| tracking_url | string | URL to track the delivery |
| courier | object | Courier service information |
| pricing_breakdown | object | Price breakdown of the order |
| shipment | object | Submitted shipment details |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| service_id | int | Courier's service ID |
| courier_name | string | Name of the courier |
| img_courier | string | Logo URL of the courier |
Pricing Breakdown
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used (e.g., MYR) |
| total_order_amount | string | Final amount before any coupon |
| total_paid_amount | string | Amount paid after coupon applied |
| shipment_amount | string | Delivery cost without tax |
| tax_amount | string | Tax applied to the shipment |
| coupon_redeemed | string | Amount discounted using the coupon |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| coupon_codes | array | Applied coupon codes (if any) |
| origin_country | string | Country code of the shipment origin |
| ondemand_service_id | string | Service ID used |
| schedule_pickup_date | string | Scheduled pickup date |
| schedule_pickup_time | string | Scheduled pickup time |
| time_zone | string | Time zone of the schedule |
| metadata | object | Additional metadata (e.g., quotationId) |
| waypoint | array | Pickup and dropoff location details |
Waypoint Object
| Parameter | Type | Description |
|---|---|---|
| point | int | Sequence point (0=pickup, 1=dropoff) |
| type | string | Type of point ('pickup'/'dropoff') |
| remark | string | Remark or notes for the waypoint |
| coordinates | object | Latitude and longitude |
| item | array | Items associated with this stop |
| shipment_info | object | Sender or receiver contact details |
Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (Requests)
fetch("https://api.easyparcel.com/ondemand/order", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
},
body: JSON.stringify({ ... })
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$ch = curl_init("https://api.easyparcel.com/ondemand/order");
$data = [ ... ];
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = "https://api.easyparcel.com/ondemand/order"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
data = { ... }
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for OnDemand Submit Order
- Validate your data before sending the request, especially coordinates and item dimensions.
- Use quotationId from the Get Quotation API in
metadatato ensure pricing consistency. - Respect rate limits by not firing too many requests in a short time.
- Ensure date and time format follow
YYYY-MM-DDandHH:MM:SSstandards. - Always include proper contact details to avoid delivery failure.
- Secure your access token and never expose it in public repositories.
- Use sandbox/test environment for testing before going live.
OnDemand Coupon
The coupon feature allows customers to search for available promo codes and apply them during the shipment order submission. This helps users enjoy discounted rates or special benefits based on current promotional campaigns.
HTTP Request (OnDemand Coupon List)
Customers can retrieve a list of available coupon codes using the following endpoint:
GET https://api.easyparcel.com/open_api/2025-12/ondemand/get_coupon_list
This will return a list of valid promo codes available to use for the shipment from the user’s account, based on factors such as delivery type, courier, or region.
OnDemand Coupon Request
Submitting to the Coupon Listing Endpoint based on the submit shipment order endpoint request to get the available coupon for the shipment
Sample Coupon Listing Request:
{
"origin_country": "MY",
"ondemand_service_id": "EP-CS0I",
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3418817446335963964"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "127849162",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "asa",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oreo",
"email": "oreo@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
OnDemand Coupon Response
Sample Respone for the coupon listing
{
"status_code": 200,
"message": "4 coupon(s) available",
"data": {
"account_id": 438368,
"currency_code": "MYR",
"coupons": [
{
"coupon_code": "77f39c22-427a-44f1-8bff-e4f3752ba165",
"title": "Test Coupon 1",
"description": "Test ",
"discounted_amount": "5.01",
"discount_rate": "20.00%",
"valid_from_date": "2025-05-12 18:04:33",
"valid_to_date": "2025-12-14 18:04:33"
},
{
"coupon_code": "10101f8b-1dc5-49e0-b4d3-09c5deb76513",
"title": "Test Coupon",
"description": "Test",
"discounted_amount": "2.34",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "dfa5109a-2f35-427e-8482-9b0ab65c323f",
"title": "Test Coupon",
"description": "Test",
"discounted_amount": "2.10",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "ad205174-d93d-4d6a-a5cc-1e989b0292eb",
"title": "Test Coupon",
"description": "Test",
"discounted_amount": "1.89",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
}
]
}
}
Coupon Listing API - Response Parameters
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| message | string | Description of the response message |
| data | object | Container for coupon and account details |
data Object
| Parameter | Type | Description |
|---|---|---|
| account_id | int | The EasyParcel account ID |
| currency_code | string | Currency in which the discount is offered (e.g., MYR) |
| coupons | array | List of coupon objects available for use |
coupon Object (Inside coupons array)
| Parameter | Type | Description |
|---|---|---|
| coupon_code | string | Unique identifier for the coupon |
| title | string | Title or name of the coupon campaign |
| description | string | Description or note about the coupon |
| discounted_amount | string | Discount value in currency terms |
| discount_rate | string | Discount in percentage (e.g., "10.00%") |
| valid_from_date | string | Start datetime of coupon validity (UTC format) |
| valid_to_date | string | End datetime of coupon validity (UTC format) |
Applying Coupons
During the order submission process (e.g., /shipment/submit or /ondemand/shipment/submit), customers can apply a valid coupon code by including it in the request body.
To apply coupon just adding the coupon_codes parameters to the request
Sample Field in Submit Orders:
{
"coupon_codes":["ad205174-d93d-4d6a-a5cc-1e989b0292eb"],
"origin_country": "MY",
"ondemand_service_id": "EP-CS0I",
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3418817446335963964"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "127849162",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Asa",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oreo",
"email": "oreo@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
If the coupon is valid and applicable, the discounted amount will be reflected in the final pricing.
Please ensure the coupon is valid and not expired before applying. For additional validation feedback, refer to the response message from the submission endpoint.
OnDemand Order Cancellation
This guide explains how to cancel an on-demand shipment order.
Endpoint URL
POST https://api.easyparcel.com/2025-12/ondemand/cancel
OnDemand Cancel Request
| Parameter | Type | Required | Description |
|---|---|---|---|
| booking_id | string | yes | booking number/id of the ondemand shipment |
-
Request Example
{
"booking_id": "EOD-150"
}
OnDemand Cancel Response
Sample Response
{
"status_code": 200,
"message": "success",
"data": [
{
"message": "Shipment cancelled successfully",
"booking_id": "EOD-150"
}
]
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code (e.g., 200) |
| message | string | Success or error message |
| data | object | Contains booking details and shipment info |
Cancellation
| Parameter | Type | Description |
|---|---|---|
| message | string | message for the cancelled status |
| booking_id | string | booking id/number of the ondemand status |
Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (Requests)
fetch("https://api.easyparcel.com/ondemand/cancel", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
},
body: JSON.stringify({
booking_id: "EOD-330"
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$ch = curl_init("https://api.easyparcel.com/ondemand/cancel");
$data = [
"booking_id" => "EOD-330"
];
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = "https://api.easyparcel.com/ondemand/cancel"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
data = {
"booking_id": "EOD-330"
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for OnDemand Cancel Order
- Always include a valid
booking_idwhen attempting to cancel an order. - Ensure the order is eligible for cancellation (i.e., not already picked up or completed).
- Handle the response gracefully, including possible failure messages.
- Use test credentials in sandbox mode for testing integration before going live.
- Rate limit your API calls to avoid service throttling or rejection.
- Log your cancellation attempts for traceability and support reference.
- Secure your access token and never expose it in public repositories or front-end code.
Account Related Endpoints
Account related will provides features related to your easyparcel account such as receiving account details.
Wallet Balance
This endpoint allows users to retrieve their current wallet balance and free credit information.
HTTP Request (Wallet)
GET https://api.easyparcel.com/open_api/2025-12/wallet
Request Wallet Parameters
This endpoint does not require any request parameters. Authentication is handled through Oauth 2.0 access token.
Request Sample for Wallet
No request body required
Response Wallet Parameters
Response Sample for Wallet
{
"status_code": 200,
"message": "Success",
"data": {
"wallet": [
{
"balance": 9999999123.88,
"currency": "MYR"
}
],
"free_credit_wallet": [
{
"balance": 0,
"currency": "MYR"
}
]
}
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | object | Contains wallet information |
Data Object
| Parameter | Type | Description |
|---|---|---|
| wallet | array | Array of wallet balances |
| free_credit_wallet | array | Array of free credit balances |
Wallet Object
| Parameter | Type | Description |
|---|---|---|
| balance | double | Available balance in the wallet |
| currency | string | Currency code of the balance |
Free Credit Wallet Object
| Parameter | Type | Description |
|---|---|---|
| balance | double | Available free credits |
| currency | string | Currency code of the free credits |
Error Response for Wallet
If there's an authentication issue or server error, the API will return an error response:
{
"status_code": 401,
"message": "Unauthorized access",
"data": null
}
Usage Notes for Wallet
- This endpoint provides the current balance in your EasyParcel wallet, which can be used for shipping services.
- The response includes both regular wallet balance and free credit balance.
- The balance is updated in real-time and reflects the current available amount for shipping services.
- Wallet balances can be topped up through the EasyParcel dashboard.
- Always ensure your account has sufficient balance before submitting shipment orders to avoid processing delays.
Webhooks
How to Subscribe to Webhooks
Prerequisites
Before setting up webhooks, ensure you have: - An active EasyParcel developer account - A configured app in the Developer Hub - A valid endpoint URL that can receive POST requests - Your endpoint configured to handle webhook payloads
Subscription Steps
Follow these steps to subscribe to webhooks:
1. 🎯 Navigate to App Settings
- Go to Developer Hub Dashboard
- Click on Apps
- Select Settings on the app you wish to configure webhooks for
2. 📡 Access Webhook Configuration
- In the left sidebar, click Webhook
- Click the Add Endpoint button
3. ⚙️ Configure Webhook Details
- Enter Endpoint URL: Input the URL that will receive the webhook payload
- Select Webhook Topic: Choose the event(s) you want to subscribe to from the available options
- Verify Configuration: Double-check your URL and selected topics
4. 💾 Save Configuration
- Press Save to confirm your webhook settings
- Your webhook endpoint will be validated
5. ✅ Confirmation
- Done! Your webhook is now active and will be triggered according to your selected topics
- Test your endpoint to ensure it's receiving webhook data correctly
Webhook Topics
| Topic ID | Webhook Topic Name | Description |
|---|---|---|
| 1 | Ondemand Order Status Update | Triggered when an on-demand order status changes |
| 2 | Shipment Status Update | Triggered when a shipment status changes |
| 3 | Shipment AWB Update | Triggered when a shipment AWB (Air Waybill) is updated |
| 4 | Tracking Status Update | Triggered when package tracking status is updated |
| 5 | Shipment Created | Triggered when a new shipment is created |
Webhook Sample Payload:
//Shipment Status Update Sample:
{
"topic": "shipment.awb.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "238725129086",
"awb_url":"http:\/\/demo.connect.easyparcel.my\/?ac=AWBLabel&id=QmIxTE43eHQjMTYzMDQwMTI%3D",
"tracking_url":"https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001523"
}
//Shipment AWB Update Sample:
{
"topic": "shipment.awb.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "23872512999",
"awb_url":"http:\/\/demo.connect.easyparcel.my\/?ac=AWBLabel&id=QmIxTE43eHQjMTYzMDQwAAA%3D",
"tracking_url":"https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001999"
}
//Shipment AWB Update Sample:
{
"topic": "shipment.tracking.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "238725129086",
"latest_shipment_status_code":5,
"latest_tracking_status": "Deliverd To Suntech",
"timestamp":"2017-10-28 11:40:00",
"status_log":[
"0":{
"timestamp":"2017-10-28 11:40:00",
"shipment_status_code":5,
"tracking_status" : "Deliverd To Suntech"
},
"1":{
"timestamp":"2017-06-28 12:00:00",
"shipment_status_code":3,
"tracking_status":"Parcel has been collected at Penang"
}
]
}
//Shipment Create Sample:
{
"shipment_number": "WEBHOOK-TEST-001",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"sender_name": "Test Sender",
"receiver_name": "Test Receiver",
"sender_phone_number": "0123456789",
"receiver_phone_number": "0987654321",
"sender_email": "sender@test.com",
"receiver_email": "receiver@test.com",
"sender_address1": "Test Address 1",
"receiver_address1": "Test Address 1",
"sender_postcode": "12345",
"receiver_postcode": "54321",
"sender_city": "Test City",
"receiver_city": "Test City",
"sender_country_code": "MY",
"receiver_country_code": "MY",
"weight": 1.0,
"length": 10,
"width": 10,
"height": 10,
"service_id": 1,
"courier_id": 1,
"status": 1
}
//Ondemand Order Status Update Sample:
{
"topic": "ondemand.status.update",
"order_number": "EODWEBHOOK-TEST-001",
"tracking_url": "https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001523",
"status": 0,
"timeline": ,
"driver": {
"id": "81994", "name": "TestDriver 09090", "phone": "+6090909090", "photo": "", "rating": "", "vehicle": {"model": "", "licensePlate": "VP5734736", "physicalVehicleType": "Bike"}, "coordinates": {"latitude": 0, "longitudelatitude": 0 }
},
"event_date": "2025-06-06 04:21:07",
"waypoint": [
{"pod": null, "coordinate": {"latitude": 5.325513957, "longitude": 100.2862732}},
{"pod": "http://sg-oimg-pre.lalamove.com/appdriver/pre/appdriver/2021/07/05/1625479646347738192598.png", "coordinate": {"latitude": 5.325513957, "longitude": 100.2862732}}
],
}
Usage Notes for Webhooks
- Multiple Subscriptions: You can subscribe to multiple topics for the same endpoint
- Event Filtering: Choose only the topics relevant to your application to reduce unnecessary webhook calls
Important Notes for Webhooks
- Endpoint Requirements: Your URL must be publicly accessible and able to handle POST requests
- Multiple Topics: You can subscribe to multiple webhook topics for the same endpoint
- Payload Format: All webhooks send JSON payloads with event-specific data
- Response Expected: Your endpoint should return a 200 status code to acknowledge receipt
- Retry Logic: Failed webhook deliveries may be retried automatically
Testing Your Webhook
After setup, verify your webhook is working: 1. Trigger a test event in your app 2. Check your endpoint logs for incoming requests 3. Verify the payload structure matches your expectations 4. Ensure your endpoint responds with HTTP 200
🛠️ Troubleshooting for webhooks
Common Issues: - Endpoint not receiving data: Verify URL is publicly accessible - SSL/HTTPS required: Ensure your endpoint uses HTTPS - Timeout errors: Your endpoint should respond quickly (within 30 seconds) - Invalid responses: Return proper HTTP status codes
References
ISO 3166
At EasyParcel, we adhere to the ISO 3166 standard for the identification of states, provinces, and zones. For example, the code "MY-07" corresponds to the state of Penang in Malaysia.
ISO 3166 is a standard published by the International Organization for Standardization (ISO) that defines codes for the names of countries, dependent territories, special areas of geographical interest, and their principal subdivisions (e.g., provinces or states). The official name of the standard is Codes for the representation of names of countries and their subdivisions. make this sentences better
Country Code
| Short Country Name | Full Country Name |
|---|---|
| SR | SURINAME |
| SD | SUDAN |
| VC | ST. VINCENT |
| XM | ST. MAARTEN |
| LC | ST. LUCIA |
| KN | ST. KITTS |
| XE | ST. EUSTATIUS |
| BL | ST. BARTHELEMY |
| LK | SRI LANKA |
| ES | SPAIN |
| ZA | SOUTH AFRICA |
| XS | SOMALILAND (NORTH SOMALIA) |
| SO | SOMALIA |
| SB | SOLOMON ISLANDS |
| SI | SLOVENIA |
| SK | SLOVAKIA |
| SG | SINGAPORE |
| SL | SIERRA LEONE |
| SC | SEYCHELLES |
| RS | SERBIA |
| SN | SENEGAL |
| SA | SAUDI ARABIA |
| ST | SAO TOME AND PRINCIPE |
| SM | SAN MARINO |
| WS | SAMOA |
| MP | SAIPAN |
| RW | RWANDA |
| RU | RUSSIAN FEDERATION |
| RO | ROMANIA |
| RE | REUNION |
| QA | QATAR |
| PR | PUERTO RICO |
| PT | PORTUGAL |
| PL | POLAND |
| PH | PHILIPPINES |
| PE | PERU |
| PY | PARAGUAY |
| PG | PAPUA NEW GUINEA |
| PA | PANAMA |
| PW | PALAU |
| PK | PAKISTAN |
| OM | OMAN |
| NO | NORWAY |
| NU | NIUE |
| NG | NIGERIA |
| NE | NIGER |
| NI | NICARAGUA |
| NZ | NEW ZEALAND |
| NC | NEW CALEDONIA |
| XN | NEVIS |
| NL | NETHERLANDS |
| NP | NEPAL |
| NR | NAURU |
| NA | NAMIBIA |
| MM | MYANMAR |
| MA | MOROCCO |
| MS | MONTSERRAT |
| ME | MONTENEGRO |
| MN | MONGOLIA |
| MC | MONACO |
| MD | MOLDOVA, REPUBLIC OF |
| FM | MICRONESIA, FEDERATED STATES OF |
| MX | MEXICO |
| YT | MAYOTTE |
| MU | MAURITIUS |
| MR | MAURITANIA |
| MQ | MARTINIQUE |
| MH | MARSHALL ISLANDS |
| MT | MALTA |
| ML | MALI |
| MV | MALDIVES |
| MW | MALAWI |
| MY | MALAYSIA |
| MG | MADAGASCAR |
| MK | MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF |
| MO | MACAU |
| LU | LUXEMBOURG |
| LT | LITHUANIA |
| LI | LIECHTENSTEIN |
| LY | LIBYA |
| LR | LIBERIA |
| LS | LESOTHO |
| LB | LEBANON |
| LV | LATVIA |
| LA | LAO PEOPLE'S DEMOCRATIC REPUBLIC |
| KG | KYRGYZSTAN |
| KW | KUWAIT |
| XK | KOSOVO |
| KR | KOREA, REPUBLIC OF |
| KP | KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF |
| KI | KIRIBATI |
| KE | KENYA |
| KZ | KAZAKHSTAN |
| JO | JORDAN |
| JE | JERSEY |
| JP | JAPAN |
| JM | JAMAICA |
| IT | ITALY |
| IL | ISRAEL |
| IE | IRELAND |
| IQ | IRAQ |
| IR | IRAN, ISLAMIC REPUBLIC OF |
| ID | INDONESIA |
| IN | INDIA |
| IS | ICELAND |
| HU | HUNGARY |
| HK | HONG KONG |
| HN | HONDURAS |
| HT | HAITI |
| GY | GUYANA |
| GW | GUINEA BISSAU |
| GN | GUINEA REPUBLIC |
| GG | GUERNSEY |
| GT | GUATEMALA |
| GU | GUAM |
| GP | GUADELOUPE |
| GD | GRENADA |
| GL | GREENLAND |
| GR | GREECE |
| GI | GIBRALTAR |
| GH | GHANA |
| DE | GERMANY |
| GE | GEORGIA |
| GM | GAMBIA |
| GA | GABON |
| ZW | ZIMBABWE |
| FR | FRANCE |
| FI | FINLAND |
| ZM | ZAMBIA |
| FJ | FIJI |
| YE | YEMEN |
| FO | FAROE ISLANDS |
| FK | FALKLAND ISLANDS (MALVINAS) |
| ET | ETHIOPIA |
| VI | VIRGIN ISLANDS, U.S. |
| EE | ESTONIA |
| VG | VIRGIN ISLANDS, BRITISH |
| ER | ERITREA |
| GQ | EQUATORIAL GUINEA |
| SV | EL SALVADOR |
| EG | EGYPT |
| VN | VIETNAM |
| EC | ECUADOR |
| TP | EAST TIMOR |
| VE | VENEZUELA |
| DO | DOMINICAN REPUBLIC |
| DM | DOMINICA |
| DJ | DJIBOUTI |
| VU | VANUATU |
| DK | DENMARK |
| CZ | CZECH REPUBLIC |
| CY | CYPRUS |
| CU | CUBA |
| UZ | UZBEKISTAN |
| UY | URUGUAY |
| HR | CROATIA |
| CI | COTE D'IVOIRE |
| CR | COSTA RICA |
| CK | COOK ISLANDS |
| CD | CONGO, THE DEMOCRATIC REPUBLIC OF THE |
| UM | UNITED STATES MINOR OUTLYING ISLANDS |
| CG | CONGO |
| KM | COMOROS |
| CN | CHINA |
| US | UNITED STATES |
| GF | FRENCH GUIANA |
| AN | NETHERLANDS ANTILLES |
| MZ | MOZAMBIQUE |
| CW | CURACAO |
| CO | COLOMBIA |
| CL | CHILE |
| TD | CHAD |
| CF | CENTRAL AFRICAN REPUBLIC |
| KY | CAYMAN ISLANDS |
| GB | UNITED KINGDOM |
| CV | CAPE VERDE |
| AE | UNITED ARAB EMIRATES |
| IC | CANARY ISLANDS, THE |
| CA | CANADA |
| UA | UKRAINE |
| CM | CAMEROON |
| KH | CAMBODIA |
| UG | UGANDA |
| BI | BURUNDI |
| BF | BURKINA FASO |
| BG | BULGARIA |
| BN | BRUNEI DARUSSALAM |
| TV | TUVALU |
| BR | BRAZIL |
| TC | TURKS AND CAICOS ISLANDS |
Add-On Feature: EasyParcel Tracking Notification
Real-time parcel tracking has become essential in today’s fast-paced logistics environment. To improve user experience and enhance transparency, EasyParcel offers multiple tracking notification methods as add-on features for standard delivery services.
📲 Tracking SMS
Tracking SMS allows recipients to receive real-time parcel status updates via SMS. Notifications are automatically sent when the parcel is dispatched, in transit, or out for delivery. This is especially helpful for users who are always on the go and prefer quick updates without logging into the platform.
📧 Tracking Email
With Tracking Email, recipients receive status updates directly in their inboxes. This is an ideal solution for users who rely heavily on email and want to maintain a full history of parcel status in one place. Updates are triggered automatically as the parcel progresses through various delivery stages.
💬 Tracking WhatsApp
WhatsApp Tracking is a modern, interactive way to stay informed about parcel movements. Notifications are delivered straight to the recipient’s WhatsApp chat, making it easy to follow updates in real-time and share parcel progress with others if needed.
These tracking features are available for EasyParcel users across various supported countries. Please refer to your local EasyParcel platform for feature availability and pricing. You may also run the Get Shipment Quotation endpoint to retrieve pricing details for available tracking features. These tracking features can be activated through the Submit Order endpoint during order creation.
EasyParcel Coupon Feature
EasyParcel’s coupon feature offers customers a convenient way to enjoy special discounts, seasonal promotions, and loyalty rewards. These promo codes help users save on shipping costs and encourage engagement through exclusive campaign offers.
🎁 What Are EasyParcel Coupons?
Coupons are promo codes issued by EasyParcel that provide instant rebates or special perks when applied to a shipment. They can be targeted based on delivery types, couriers, regions, or customer eligibility (e.g., new users, festive deals).
🔍 Where to Find Coupons
Customers can browse available coupons directly through the EasyParcel platform. These offers may appear on promotional banners, in user dashboards, or be provided via campaigns. Developers can also retrieve available coupons programmatically using the designated API endpoint.
🧾 How to Use Coupons
To enjoy a discount, users simply need to enter the valid coupon code during order submission. If the coupon meets the required conditions, the discount will be reflected in the final price.
Please note that coupon availability and eligibility may vary by country, courier, and shipping method. Always check the terms associated with each coupon before use.
Cancel Order
This section introduces the cancellation features available for both standard and ondemand shipments on the EasyParcel platform.
❗ Important Cancellation Conditions
- 7-Day Limit: Cancellation requests must be submitted within 7 days from the scheduled collection date.
- No Cancellation After Pickup: Once the courier driver has picked up the parcel, cancellation is no longer permitted.
- Refunds: If the cancellation is successful, the shipment cost will be refunded to the user's credit wallet.
📡 Relevant Endpoints
Bulk Cancellation Support:
- Standard shipments support bulk cancellation.
- Ondemand shipments must be cancelled individually.
/shipment/cancel– for standard shipment cancellations./ondemand/shipment/cancel– for ondemand shipment cancellations.
EasyParcel API Standards
This document outlines the standard formats for requests and responses when working with the EasyParcel API.
Request Format Standards
General Guidelines
- All requests must be sent as HTTP POST requests
- Content-Type header should be set to
application/json - Authentication is handled via Oauth 2.0 access token in the headers
- All request payloads should be valid JSON objects
- DateTime values should use the format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS
Common Request Structure
Most EasyParcel API endpoints follow a consistent request format:
Single Resource Requests - Simple requests with a single parameter set:
json { "parameter1": "value1", "parameter2": "value2" }Batch Requests - Requests involving multiple items follow an array pattern:
json { "resource_name": [ { /* item 1 details */ }, { /* item 2 details */ } ] }
Example Request Types
Shipment Submission
Batch format with shipment array containing multiple shipment objects:
{
"shipment": [
{
"service_id": "EP-CS09Q",
"collection_date": "2025-05-02",
"weight": 2.5,
"height": 30,
"length": 40,
"width": 20,
"item": [ /* items array */ ],
"sender": { /* sender details */ },
"receiver": { /* receiver details */ },
"feature": { /* feature settings */ }
},
// Additional shipments...
]
}
Quotation Request
Similar batch format with shipment array containing multiple quote requests:
{
"shipment": [
{
"sender": {
"postcode": "10150",
"subdivision_code": "MY-02",
"country": "MY"
},
"receiver": {
"postcode": "018916",
"subdivision_code": "SG-04",
"country": "SG"
},
"parcel_value": 50,
"weight": 0.5,
"width": 5,
"length": 5,
"height": 5
},
// Additional quote requests...
]
}
Shipment Listing Request
Simple parameter format for filtering and pagination:
{
"limit": 3,
"before_shipment_number": "ES-2504-B944M",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Response Format Standards
General Guidelines
- All responses are returned as JSON objects
- Every response includes
status_code,message, anddatafields - Successful operations return status code 200
- Error details are provided in both the message and data sections
- Batch operations provide individual success/failure information for each item
Common Response Structure
Success Response Patterns
/* Single Resource Response */
{
"status_code": 200,
"message": "success",
"data": [
/* Response data objects */
]
}
/* Batch Operation Response */
{
"status_code": 200,
"message": "2 requests success, 1 request error.",
"data": [
{
"status": "success",
"message": "Order Processed",
"item_id": "12345"
},
{
"status": "success",
"message": "Order Processed",
"item_id": "12346"
},
{
"status": "error",
"message": "Invalid postal code",
"item_id": "12347"
}
]
}
Error Response Patterns
/* Request Validation Error */
{
"status_code": 400,
"message": "Validation failed",
"data": {
"errors": [
"The service_id field is required",
"The collection_date field is required"
]
}
}
/* Resource Not Found */
{
"status_code": 404,
"message": "No Order with shipment_number ES-2504-3WYYP found from this account",
"data": []
}
/* Authentication Error */
{
"status_code": 401,
"message": "Invalid Oauth 2.0 access token",
"data": null
}
/* Partial Success in Batch Operations */
{
"status_code": 200,
"message": "1 requests success, 2 request error.",
"data": [
{
"status": "success",
"message": "Order Cancelled",
"shipment_number": "ES-2504-WZ9VY"
},
{
"status": "error",
"message": "Shipment Already Cancelled",
"shipment_number": "ES-2504-JUB4T"
},
{
"status": "error",
"message": "Shipment Not Found",
"shipment_number": "ES-2504-INVALID"
}
]
}
Common Field Types
| Field Type | Format | Example |
|---|---|---|
| Date | YYYY-MM-DD | 2025-05-02 |
| DateTime | YYYY-MM-DD HH:MM:SS | 2025-05-02 14:30:00 |
| Weight | Numeric (kg) | 2.5 |
| Dimensions | Numeric (cm) | 30 |
| Currency | ISO Currency Code | MYR |
| Country Code | ISO Country Code | MY |
| Subdivision Code | ISO 3166-2 code | MY-07 |
| Phone Code | With "+" prefix | +60 |
| Boolean | true/false | true |
Best Practices
- Validate Input: Always validate request parameters against the API documentation before submission
- Check Status Codes: Always check the status_code in the response
- Handle Batch Responses: For batch operations, check individual status values for each item
- Error Handling: Implement proper error handling based on the error message patterns
- Pagination: For list endpoints, use the provided pagination mechanisms with
limitandbefore_shipment_number - Date Ranges: When using date ranges, ensure
date_fromis earlier thandate_to - Field Lengths: Respect the maximum field lengths specified in the API documentation
-
Notes on API Versioning
The API version is included in the URL path: /2025-12/
Always use the appropriate version for your implementation to ensure compatibility.
EasyParcel API Error Handling Guide
This document outlines the common error patterns and recommended handling strategies when working with the EasyParcel API.
Error Response Patterns
The EasyParcel API returns specific error formats depending on the type of error encountered. Understanding these patterns will help you implement proper error handling in your integration.
Authentication Errors
When authentication fails, you'll receive a response in this format:
{
"error": {
"statusCode": 401,
"status": 401,
"code": 401,
"name": "invalid_token"
},
"status_code": 401
}
Common Authentication Error Codes
| Error Name | Description | Recommended Action |
|---|---|---|
| invalid_token | The Oauth 2.0 access token is invalid or expired | Verify your Oauth 2.0 access token and request a new one if needed |
| missing_token | No Oauth 2.0 access token was provided in the request | Ensure Oauth 2.0 access token is included in the request header |
| insufficient_scope | The Oauth 2.0 access token doesn't have permission for this action | Request appropriate permissions for your Oauth 2.0 access token |
Validation Errors
Single Resource Validation
For single resource operations with validation errors:
{
"status_code": 400,
"message": "Validation error",
"data": {
"errors": [
"The service id field is required",
"The collection date field is required"
]
}
}
Batch Operation Errors
For batch operations, the API may return a mix of successful and failed operations:
Complete Batch Failure
{
"status_code": 200,
"message": "0 requests success, 3 request error.",
"data": [
{
"order_details": {
"account_id": "438671"
},
"pricing": {
"currency_code": "MYR",
"total_amount": "0.00",
"total_tax_amount": "0.00"
},
"shipments": [
{
"status": "error",
/* shipment details */
"errors": [
"The service id field is required",
"The collection date field is required",
"The receiver phone number country code field is required",
"The receiver phone number field is required",
"The receiver address 1 field is required"
]
},
/* additional failed shipments */
]
}
]
}
Partial Success in Batch Operations
{
"status_code": 200,
"message": "1 request success, 1 request error.",
"data": [
{
"order_details": {
"order_number": "EI-2504-6WFXC",
"account_id": 438671
},
"pricing": {
"currency_code": "MYR",
"total_amount": "27.83",
"total_tax_amount": "1.63"
},
"shipments": [
{
"status": "success",
/* successful shipment details */
},
{
"status": "error",
/* failed shipment details */
"errors": [
"The service id field is required",
"The collection date field is required"
]
}
]
}
]
}
Quotation Errors
Quotation endpoints also follow the batch processing pattern, where some items may succeed while others fail:
{
"status_code": 200,
"message": "1 request success, 2 request error.",
"data": [
{
"status": "success",
"input": { /* input details */ },
"quotations": [ /* quotation results */ ]
},
{
"status": "error",
"input": { /* input details */ },
"errors": [
"The receiver postcode is invalid"
]
},
{
"status": "error",
"input": { /* input details */ },
"errors": [
"The receiver country field is required"
]
}
]
}
Common Error Messages
Here are some common error messages you may encounter and how to resolve them:
Request Validation Errors
| Error Message | Possible Cause | Resolution |
|---|---|---|
| "The service id field is required" | Missing service_id in request | Include a valid service_id from courier list |
| "The collection date field is required" | Missing or invalid collection_date | Provide a valid date in YYYY-MM-DD format |
| "The receiver phone number field is required" | Missing receiver phone number | Include the receiver's phone number |
| "The receiver address 1 field is required" | Missing primary address line | Include the first line of the receiver's address |
| "The receiver postcode is invalid" | Invalid or non-existent postal code | Verify the postal code with the courier service |
| "The receiver country field is required" | Missing country code | Include a valid country code (e.g., "MY" for Malaysia) |
Business Logic Errors
| Error Message | Possible Cause | Resolution |
|---|---|---|
| "Shipment Already Cancelled" | Attempting to cancel an already cancelled shipment | Check shipment status before cancellation request |
| "No Order with shipment_number X found" | Incorrect shipment number or not owned by account | Verify the shipment number belongs to your account |
| "Shipment Cannot Be Cancelled" | Shipment is in a state that can't be cancelled | Only shipments in certain states can be cancelled |
| "Weight exceeds service limits" | Parcel exceeds courier weight restrictions | Choose a different service or reduce parcel weight |
| "Service not available for origin/destination" | Route not serviced by selected courier | Choose a different courier service |
Error Handling Best Practices
1. Check Status Code and Message
Always check both the status_code and message fields to properly identify errors. A 200 status code does not always mean complete success in batch operations.
2. Handle Batch Operations Carefully
For batch operations:
- Parse the message field to determine success/error counts
- Iterate through each item in the data array
- Check the status field of each item
- Process successful items and handle errors for failed items
3. Implement Retry Logic
For transient errors (e.g., network issues, temporary service unavailability), implement a retry mechanism with exponential backoff.
4. Log Detailed Error Information
Log detailed error information for troubleshooting, including: - Request parameters - Complete error response - Timestamp - API endpoint
5. Handle Validation Errors Proactively
Implement client-side validation based on known API requirements to reduce validation errors.
6. Check for Partial Success
Always assume batch operations may partially succeed and handle accordingly:
// Example handling of a batch response
function handleBatchResponse(response) {
console.log(`Processing response: ${response.message}`);
if (response.status_code !== 200) {
return handleNonSuccessStatusCode(response);
}
// Extract success/failure counts from message
const messageParts = response.message.split(',');
const successCount = parseInt(messageParts[0].match(/\d+/)[0]);
const errorCount = parseInt(messageParts[1].match(/\d+/)[0]);
console.log(`Shipments: ${successCount} successful, ${errorCount} failed`);
// Process data
response.data.forEach(order => {
if (order.shipments) {
order.shipments.forEach(shipment => {
if (shipment.status === 'success') {
processSuccessfulShipment(shipment);
} else {
handleFailedShipment(shipment);
}
});
}
});
}
Authentication Error Recovery
If you encounter authentication errors:
- Verify your Oauth 2.0 access token is correct
- Check if your Oauth 2.0 access token has expired
- Request a new Oauth 2.0 access token if necessary
- Ensure your system securely stores the Oauth 2.0 access token
- Implement automatic token refresh if supported
Common HTTP Status Codes
| Status Code | Description | Handling Strategy |
|---|---|---|
| 200 | Success (may include errors) | Check message and individual item status |
| 400 | Bad Request | Fix request parameters based on error details |
| 401 | Unauthorized | Refresh or update API credentials |
| 403 | Forbidden | Request appropriate permissions |
| 404 | Not Found | Verify resource identifiers |
| 429 | Too Many Requests | Implement rate limiting and backoff strategy |
| 500 | Server Error | Retry with exponential backoff |
Troubleshooting Guide
Oauth 2.0 access token Issues
- Ensure Oauth 2.0 access token is not expired
- Verify Oauth 2.0 access token is correctly included in the authorization header
- Check if your account has the necessary permissions
Invalid Input
- Validate all required fields are present
- Ensure postal codes are valid for the respective countries
- Verify dimensions and weights are within courier limitations
Service Availability
- Check if selected service is available for the specific route
- Verify the courier is operational on the requested collection date
- Confirm service availability for international routes
Shipment Status Issues
- Verify shipment status before attempting to modify or cancel
- Check if the shipment number exists and belongs to your account
- Ensure operations are performed within allowed timeframes (e.g., cancellation window)
Contact Support
If you encounter persistent errors that cannot be resolved through this guide, contact EasyParcel support with the following information:
- Complete request and response details
- Timestamp of the request
- API endpoint used
- Description of the expected vs. actual behavior
- Steps taken to troubleshoot the issue
Pagination Guide for EasyParcel API
This document outlines the pagination mechanism used in the EasyParcel API for endpoints that return multiple records, such as shipment listings and on-demand service listings.
Pagination Overview
EasyParcel API uses cursor-based pagination for list endpoints. This method is more efficient than traditional page number-based pagination, especially for large datasets.
How Pagination Works
- You specify a limit of records to return in each request
- The API returns records sorted by the latest first
- To retrieve the next set of records, you use the last record's identifier as a cursor
Pagination Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Number of records to return (default: 10, max: 250) |
| before_shipment_number | string | No | ID of the record to paginate from |
Additionally, you can use filtering parameters along with pagination:
| Parameter | Type | Required | Description |
|---|---|---|---|
| shipment_status_code | string | No | Filter by shipment status |
| date_from | date | No | Start date for filtering (YYYY-MM-DD) |
| date_to | date | No | End date for filtering (YYYY-MM-DD) |
Pagination Example
Initial Request
The first request does not include a before_shipment_number parameter:
{
"limit": 3,
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Subsequent Requests
For the next batch of records, include the before_shipment_number from the last record in the previous response:
{
"limit": 3,
"before_shipment_number": "ES-2504-B944M",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Implementation Guide
Client-Side Pagination Logic
Here's a pseudocode example of how to implement pagination in your client application:
// Initial request - no cursor
let params = {
limit: 20,
shipment_status_code: "7",
date_from: "2025-04-01",
date_to: "2025-04-23"
};
async function fetchAllShipments() {
let allShipments = [];
let hasMoreRecords = true;
while (hasMoreRecords) {
const response = await apiRequest('/shipment/list', params);
// Add fetched shipments to our collection
allShipments = [...allShipments, ...response.data];
// If we received fewer records than requested, we've reached the end
if (response.data.length < params.limit) {
hasMoreRecords = false;
} else {
// Set cursor for next request using the last record's ID
const lastShipment = response.data[response.data.length - 1];
params.before_shipment_number = lastShipment.shipment_number;
}
}
return allShipments;
}
Loading Records On Demand
For user interfaces, you may want to implement "load more" functionality:
let currentParams = {
limit: 20,
shipment_status_code: "7"
};
let shipments = [];
async function loadMoreShipments() {
const response = await apiRequest('/shipment/list', currentParams);
// Add new shipments to the existing list
shipments = [...shipments, ...response.data];
// Update button state
const loadMoreButton = document.getElementById('load-more');
if (response.data.length < currentParams.limit) {
loadMoreButton.style.display = 'none'; // Hide when no more records
} else {
// Update cursor for next request
const lastShipment = response.data[response.data.length - 1];
currentParams.before_shipment_number = lastShipment.shipment_number;
}
// Update UI with new shipments
renderShipments(shipments);
}
Pagination for On-demand Listings
The on-demand listing endpoint (/open_api/2025-12/ondemand/list) follows the same pagination pattern as shipment listings, but uses before_booking_number instead of before_shipment_number:
{
"limit": 3,
"before_booking_number": "EOD-123",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Best Practices
- Default Limit: If not specified, the API uses a default limit of 10 records per request
- Maximum Limit: The maximum limit is 250 records per request
- Sort Order: Results are always sorted with the most recent records first
- Filter Efficiency: Use status and date filters to reduce the dataset before pagination
- Cursor Storage: Always store the last cursor for error recovery
- Empty Results: If a request returns empty results, you've reached the end of the dataset
Common Issues and Solutions
| Issue | Solution |
|---|---|
| Missing records in pagination sequence | Ensure you're using the correct cursor value |
| Too many API calls for large datasets | Increase the limit parameter (up to 250) |
| Need to restart pagination from beginning | Remove the before_shipment_number parameter |
| Results not matching expected criteria | Review filter parameters for correct formatting |
Notes on Resource Usage
- Using appropriate limit values and filters helps reduce API calls
- Retrieving all records in smaller batches is more reliable than requesting large batches
- Consider implementing caching for frequently accessed records
Switching to Live
If you've completed testing in the DEMO/Sandbox environment and would like to switch to the live environment, please follow the steps below:
- Run the "Get New Access Token" flow.
- Once you reach the "Select Account" section, choose and switch to your live account.
That's it! You have successfully switched to the live environment.
Version (2025-09)
Here we will provide you with the latest version of the EasyParcel API, along with any important changes or updates.
Standard Shipping
Standard shipping provides scheduled delivery with cost-effective solutions for businesses with regular shipping needs. This service offers comprehensive tracking, multiple courier options, and flexible additional features.
Shipping Workflow
Standard Shipping Flow
├── Order Flow
│ ├── Get Quotation
│ ├── Get Coupon Listing
│ └── Submit Order
└── Management Flow
├── Get Shipment Listing
├── Get Shipment Details
└── Cancel Orders
Shipment Quotations
Get shipment quotations from all available courier companies on the EasyParcel platform. Provide sender and receiver addresses to receive pricing details, available services, and additional features.
Authentication (Standard Quotation)
To authorize, use this code:
curl "https://api.easyparcel.com/open_api/2025-09/shipment/quotations" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
const headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
};
$headers = [
'Authorization: Bearer YOUR_ACCESS_TOKEN',
'Content-Type: application/json'
];
headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
}
EasyParcel uses Oauth 2.0 to allow access to the API. You can register a new Oauth 2.0 access at our developer portal.
The API expects the Oauth 2.0 to be included in all API requests to the server in a header that looks like the following:
Authorization: Bearer YOUR_ACCESS_TOKEN
HTTP Request (Quotation)
POST https://api.easyparcel.com/open_api/2025-09/shipment/quotations
Quotation Request
Example Request:
{
"shipment": [
{
"sender": {
"postcode": "10150",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "11950",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value":50,
"weight": 1.5,
"width": 5,
"length": 5,
"height": 5
}
]
}
Sender Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string(10) | true | Sender's postcode |
| subdivision_code | string(35) | true | Sender's subdivision code (ISO 3166) |
| country | string(2) | true | Sender's country code |
Receiver Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string(10) | true | Receiver's postcode |
| subdivision_code | string(35) | true | Receiver's subdivision code (ISO 3166) |
| country | string(2) | true | Receiver's country code |
Parcel Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| weight | double(8,2) | true | Parcel weight in KG |
| width | double(8,2) | false | Parcel width in CM |
| height | double(8,2) | false | Parcel height in CM |
| length | double(8,2) | false | Parcel length in CM |
| parcel_value | double(8,2) | false | Parcel value in account currency |
Quotation Response
Example Response:
{
"status_code": 200,
"request_id": "1770285829860.591d8c4f-ca8d-4e8b-9871-28e86ae541d9",
"message": "1 request success, 0 request error.",
"data": [
{
"status": "success",
"input": {
"sender": {
"postcode": "10150",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "11950",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value": 50,
"weight": 1.5,
"width": 5,
"length": 5,
"height": 5
},
"quotations": [
{
"courier": {
"service_id": "EP-CS096",
"service_name": "Aramex (Pick Up)",
"courier_id": "EP-CR0AP",
"courier_name": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Aramex.jpg",
"delivery_duration": null,
"service_tag": [
{
"name": "Service Destinations",
"value": "Domestic"
},
{
"name": "Service Methods",
"value": "Pick Up from Door"
},
{
"name": "Service Methods",
"value": "Deliver to Door"
},
{
"name": "Tracking Quality",
"value": "Regular"
},
{
"name": "Supported AWB",
"value": "Supported AWB size: A6"
}
]
},
"pricing": {
"currency": "MYR",
"total_amount": "10.84",
"shipment_price": "9.80",
"shipment_tax": "0.59",
"total_features_price": "0.45",
"total_features_tax": "0.00"
},
"features": [
{
"cod": {
"available": true,
"min_cod_amount": "MYR10.00",
"max_cod_amount": "MYR1000.00",
"min_cod_charges": "MYR10.00",
"cod_charging_rate": "4.00%",
"charges_description": "4.00% of the parcel value or MYR10.00, whichever is higher"
}
},
{
"sms_tracking": {
"sms_price": "0.20",
"custom_sms_price": "0.05",
"remove_ep_branding_price": "0.05",
"sms_tax": "0.00",
"custom_sms_tax": "0.00",
"remove_ep_branding_tax": "0.00"
}
},
{
"email_tracking": {
"email_price": "0.05",
"custom_email_price": "0.05",
"remove_ep_branding_price": "0.05",
"email_tax": "0.00",
"custom_email_tax": "0.00",
"remove_ep_branding_tax": "0.00"
}
},
{
"whatsapp_tracking": {
"whatsapp_price": "0.20",
"whatsapp_tax": "0.00"
}
}
]
}
]
}
]
}
Quotation Response
| Parameter | Type | Description |
|---|---|---|
| status_code | integer | HTTP status code |
| message | string | Response message summary |
| data | array | Array containing quotation results |
Data Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Request status (success/error) |
| input | object | Echo of input parameters |
| quotations | array | Available courier quotations |
Quotation Object
Each quotation contains detailed information about available shipping options:
Courier Information
| Parameter | Type | Description |
|---|---|---|
| service_id | string | Unique service identifier |
| service_name | string | Human-readable service name |
| courier_id | string | Unique courier identifier |
| courier_name | string | Courier company name |
| courier_logo | string | URL to courier logo image |
| delivery_duration | string/null | Expected delivery time |
| service_tag | array | Service categorization tags |
Pricing Information
| Parameter | Type | Description |
|---|---|---|
| currency | string | Currency code (e.g., MYR, USD) |
| total_amount | string | Final total including all fees |
| shipment_price | string | Base shipping price |
| total_features_price | string | Additional features cost |
Service Tags
Service tags provide categorization for different shipping services:
| Tag Name | Possible Values | Description |
|---|---|---|
| Service Label | Standard, Economy, Priority, EXD | Service speed/tier |
| Service Destinations | International, Domestic | Geographic scope |
| Service Methods | Pick Up, Drop-Off | Collection method |
Available Features
The API returns various optional features that can be added to shipments:
Cash on Delivery (COD)
available: Whether COD is supportedmin_cod_amount/max_cod_amount: COD limitscharges_description: Additional fee information
Tracking Services
sms_tracking: SMS notification pricingemail_tracking: Email notification pricingwhatsapp_tracking: WhatsApp notification pricing
Branding Options
awb_branding: Custom branding on shipping labels- Includes banner and text customization pricing
International Shipping
ddp_charges: Delivered Duty Paid charges- Includes import taxes, duties, and handling fees
Code Examples
Select a language from the options on the right to switch between PHP, JavaScript, and Python examples.
async function getShippingQuotes(senderPostcode, receiverPostcode) {
const requestData = {
list: [{
sender: {
postcode: senderPostcode,
subdivision_code: "MY-07",
country: "MY"
},
receiver: {
postcode: receiverPostcode,
subdivision_code: "MY-07",
country: "MY"
},
weight: 1.5,
width: 5,
length: 5,
height: 5,
parcel_value: 50
}]
};
try {
const response = await fetch(
'https://api.easyparcel.com/open_api/2025-09/shipment/quotations',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(requestData)
}
);
const data = await response.json();
if (data.status_code === 200) {
const quotations = data.data[0].quotations;
// Sort by price (lowest first)
quotations.sort((a, b) =>
parseFloat(a.pricing.total_amount) - parseFloat(b.pricing.total_amount)
);
return quotations;
} else {
throw new Error(data.message);
}
} catch (error) {
console.error('Failed to fetch quotations:', error);
throw error;
}
}
<?php
function getShippingQuotes($senderPostcode, $receiverPostcode) {
$requestData = [
'list' => [[
'sender' => [
'postcode' => $senderPostcode,
'subdivision_code' => 'MY-07',
'country' => 'MY'
],
'receiver' => [
'postcode' => $receiverPostcode,
'subdivision_code' => 'MY-07',
'country' => 'MY'
],
'weight' => 1.5,
'width' => 5,
'length' => 5,
'height' => 5,
'parcel_value' => 50
]]
];
$ch = curl_init('https://api.easyparcel.com/open_api/2025-09/shipment/quotations');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('cURL error: ' . curl_error($ch));
}
curl_close($ch);
$data = json_decode($response, true);
if ($data['status_code'] === 200) {
$quotations = $data['data'][0]['quotations'];
// Sort by price (lowest first)
usort($quotations, function($a, $b) {
return floatval($a['pricing']['total_amount']) -
floatval($b['pricing']['total_amount']);
});
return $quotations;
} else {
throw new Exception($data['message']);
}
}
?>
import requests
import json
def get_shipping_quotes(sender_postcode, receiver_postcode):
"""Get shipping quotations for a parcel."""
request_data = {
"list": [{
"sender": {
"postcode": sender_postcode,
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": receiver_postcode,
"subdivision_code": "MY-07",
"country": "MY"
},
"weight": 1.5,
"width": 5,
"length": 5,
"height": 5,
"parcel_value": 50
}]
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
try:
response = requests.post(
'https://api.easyparcel.com/open_api/2025-09/shipment/quotations',
headers=headers,
data=json.dumps(request_data)
)
data = response.json()
if data['status_code'] == 200:
quotations = data['data'][0]['quotations']
# Sort by price (lowest first)
quotations.sort(key=lambda x: float(x['pricing']['total_amount']))
return quotations
else:
raise Exception(data['message'])
except requests.exceptions.RequestException as e:
raise Exception(f"API request failed: {str(e)}")
Error Handling
Error Response Example:
{
"status_code": 200,
"message": "0 requests success, 1 request error.",
"data": [
{
"status": "error",
"input": {
"sender": {
"postcode": "10150",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value": 50,
"weight": 1.5,
"width": 5,
"length": 5,
"height": 5
},
"errors": [
"The receiver postcode field is required "
]
}
]
}
The API uses conventional HTTP response codes to indicate success or failure. In addition, the response body contains detailed error information.
HTTP Status Codes
| Code | Meaning |
|---|---|
| 200 | OK -- Request successful (check individual data status) |
| 400 | Bad Request -- Invalid parameters |
| 401 | Unauthorized -- Invalid Oauth 2.0 access token |
| 404 | Not Found -- Endpoint not found |
| 429 | Too Many Requests -- Rate limit exceeded |
| 500 | Internal Server Error -- Server error |
Error Response Structure
| Parameter | Type | Description |
|---|---|---|
| status | string | Always "error" for failed requests |
| input | object | The input that caused the error |
| errors | array | List of specific error messages |
Best Practices for Shipping Quotation
Input Validation
Always validate input parameters before making API requests:
- Verify postcode formats for different countries
- Ensure weight and dimensions are positive numbers
- Check country and subdivision codes against ISO standards
Rate Limiting
The API implements rate limiting to ensure fair usage:
- Batch multiple shipment quotes in a single request when possible
- Implement exponential backoff for 429 responses
- Cache responses when appropriate to reduce API calls
User Experience
To provide the best user experience:
- Sort quotations by price (ascending) by default
- Display courier logos and service names clearly
- Show delivery duration when available
- Allow users to toggle optional features
- Highlight popular or recommended services
Coupon Feature
The coupon feature allows customers to search for available promo codes and apply them during the shipment order submission. This helps users enjoy discounted rates or special benefits based on current promotional campaigns.
Searching for Coupons
Customers can retrieve a list of available coupon codes using the following endpoint:
HTTP Request (Coupon)
GET https://api.easyparcel.com/open_api/2025-09/shipment/get_coupon_list
This will return a list of valid promo codes available to use for the shipment from the user’s account, based on factors such as delivery type, courier, or region.
Coupon Request
Submitting to the Coupon Listing Endpoint based on the submit shipment order endpoint request to get the available coupon for the shipment
Sample Coupon Listing Request:
{
"shipment": [
{
"service_id": "EP-CS096",
"collection_date": "2025-05-19",
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"item": [
{
"content": "Electronics",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 2
}
],
"sender": {
"name": "John Doe",
"company": "ABC Corp",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"email": "test@easyparcel.com",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"postcode": "10150",
"city": "Lunas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"receiver": {
"name": "Jane Smith",
"company": "XYZ Inc",
"phone_number_country_code": "MY",
"phone_number": "1163042981",
"email": "test@easyparcel.com",
"address_1": "456 High St",
"address_2": "Floor 2",
"postcode": "11950",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"feature": {
"sms_tracking": true,
"email_tracking": true,
"whatsapp_tracking": true,
"awb_branding": false
}
}
]
}
Coupon Respond
Coupon Listing API - Response Parameters
Sample Respone for the courier listing
{
"status_code": 200,
"message": "4 coupon(s) available",
"data": {
"account_id": 438368,
"currency_code": "MYR",
"coupons": [
{
"coupon_code": "77f39c22-427a-44f1-8bff-e4f3752ba165",
"title": "Test Coupon 1",
"description": "Test ",
"discounted_amount": "5.01",
"discount_rate": "20.00%",
"valid_from_date": "2025-05-12 18:04:33",
"valid_to_date": "2025-09-14 18:04:33"
},
{
"coupon_code": "10101f8b-1dc5-49e0-b4d3-09c5deb76513",
"title": "Test Coupon",
"description": "Test ",
"discounted_amount": "2.34",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "dfa5109a-2f35-427e-8482-9b0ab65c323f",
"title": "Test Coupon",
"description": "Test ",
"discounted_amount": "2.10",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "ad205174-d93d-4d6a-a5cc-1e989b0292eb",
"title": "Test Coupon",
"description": "Test ",
"discounted_amount": "1.89",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
}
]
}
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| message | string | Description of the response message |
| data | object | Container for coupon and account details |
data Object
| Parameter | Type | Description |
|---|---|---|
| account_id | int | The EasyParcel account ID |
| currency_code | string | Currency in which the discount is offered (e.g., MYR) |
| coupons | array | List of coupon objects available for use |
coupon Object (Inside coupons array)
| Parameter | Type | Description |
|---|---|---|
| coupon_code | string | Unique identifier for the coupon |
| title | string | Title or name of the coupon campaign |
| description | string | Description or note about the coupon |
| discounted_amount | string | Discount value in currency terms |
| discount_rate | string | Discount in percentage (e.g., "10.00%") |
| valid_from_date | string | Start datetime of coupon validity (UTC format) |
| valid_to_date | string | End datetime of coupon validity (UTC format) |
Applying Coupons
During the order submission process (e.g., /shipment/submit or /ondemand/shipment/submit), customers can apply a valid coupon code by including it in the request body.
To apply coupon just adding the coupon_codes parameters to the request
Sample Field in submit orders:
{
"coupon_codes" :["77f39c22-427a-44f1-8bff-e4f3752ba165"],
"shipment": [
{
// as per the shipment details
}
]
}
If the coupon is valid and applicable, the discounted amount will be reflected in the final pricing.
Please ensure the coupon is valid and not expired before applying. For additional validation feedback, refer to the response message from the submission endpoint.
Submit Orders
This feature enables users to submit shipment orders. Users are required to fill in the necessary fields to access the shipping service.
HTTP Request (Submit)
POST https://api.easyparcel.com/shipment/submit_orders
Submit Order Request
Request Sample
{
"coupon_codes": [
"77f39c22-427a-44f1-8bff-e4f3752ba165"
],
"shipment": [
{
"service_id": "EP-CS096",
"collection_date": "2025-05-19",
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"item": [
{
"content": "Electronics",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 2
}
],
"sender": {
"name": "John Doe",
"company": "ABC Corp",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"email": "test@easyparcel.com",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"postcode": "10150",
"city": "Lunas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"receiver": {
"name": "Jane Smith",
"company": "XYZ Inc",
"phone_number_country_code": "MY",
"phone_number": "1163042981",
"email": "test@easyparcel.com",
"address_1": "456 High St",
"address_2": "Floor 2",
"postcode": "11950",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"feature": {
"sms_tracking": true,
"email_tracking": true,
"whatsapp_tracking": true,
"awb_branding": false
}
},
{
"service_id": "EP-CS09C",
"collection_date": "2025-05-19",
"weight": 1.5,
"height": 30,
"length": 40,
"width": 20,
"item": [
{
"content": "Electronics",
"weight": 1,
"height": 30,
"length": 40,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 10,
"length": 20,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1
}
],
"sender": {
"name": "John Doe",
"company": "ABC Corp",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"email": "test@easyparcel.com",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"postcode": "10150",
"city": "Lunas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"receiver": {
"name": "Jane Smith",
"company": "XYZ Inc",
"phone_number_country_code": "MY",
"phone_number": "1163042981",
"email": "test@easyparcel.com",
"address_1": "456 High St",
"address_2": "Floor 2",
"postcode": "11950",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"feature": {
"sms_tracking": false,
"email_tracking": true,
"whatsapp_tracking": true,
"awb_branding": false
}
}
]
}
Main Structure
| Parameter | Type | Required | Description |
|---|---|---|---|
| shipment | array | Yes | Array of shipment orders |
Shipment Object
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| service_id | string(10) | Yes | Service Identification number | - |
| collection_date | date | Yes | Date to collect the parcel | Format: YYYY-MM-DD |
| customer_reference_no | string | No | Customer reference number | - |
| weight | double(8,2) | Yes | Weight of the parcel | in KG |
| unit | string | No | Unit of measurement | - |
| height | double(8,2) | Yes | Height of the parcel | in CM |
| length | double(8,2) | Yes | Length of the parcel | in CM |
| width | double(8,2) | Yes | Width of the parcel | in CM |
| item | array | Yes | Items in the parcel | refer to item |
| sender | object | Yes | Origin of the parcel | refer to sender |
| receiver | object | Yes | Destination of the parcel | refer to receiver |
| feature | object | Yes | Additional service features | refer to feature |
Sender
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| name | string | Yes | Sender's Name | - |
| company | string | No | Sender's Company | - |
| phone_number_country_code | string | Yes | ISO 3166-1 Alpha-2 Country code of the Phone number | Example: "MY" |
| phone_number | string | Yes | Sender's phone number | - |
| alternate_phone_number_country_code | string | No | ISO Country code for alternate phone number | - |
| alternate_phone_number | string | No | Sender's alternate phone number | - |
| string | No | Sender's email | - | |
| address_1 | string | Yes | Sender's address | - |
| address_2 | string | No | Sender's address (continued) | - |
| postcode | string | Yes | Sender's postcode | - |
| city | string | Yes | Sender's city/town | - |
| subdivision_code | string | No | Sender's state/province code | Example: "MY-07" |
| country_code | string(2) | Yes | The origin country of the parcel | Example: "MY" |
| point_code | string | No | A unique identifier for sender location | - |
Receiver
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| name | string | Yes | Receiver's Name | - |
| company | string | No | Receiver's Company | - |
| phone_number_country_code | string | Yes | ISO 3166-1 Alpha-2 Country code of the Phone number | Example: "MY" |
| phone_number | string | Yes | Receiver's phone number | - |
| alternate_phone_number_country_code | string | No | Country code for alternate phone number | - |
| alternate_phone_number | string | No | Receiver's alternate phone number | - |
| string | No | Receiver's email | - | |
| address_1 | string | Yes | Receiver's address | - |
| address_2 | string | No | Receiver's address (continued) | - |
| postcode | string | Yes | Receiver's postcode | - |
| city | string | Yes | Receiver's city/town | - |
| subdivision_code | string | No | Receiver's state/province code | Example: "MY-07" |
| country_code | string(2) | Yes | The destination country of the parcel | Example: "MY" |
| point_code | string | No | A unique identifier for receiver location | - |
Feature
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| sms_tracking | boolean | No | Enable SMS tracking notifications | Default: false |
| email_tracking | boolean | No | Enable email tracking notifications | Default: false |
| whatsapp_tracking | boolean | No | Enable WhatsApp tracking notifications | Default: false |
| awb_branding | object | No | Airway bill branding | refer to awb_branding |
| cod | object | No | Cash on Delivery | refer to cod |
awb_branding
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| enable | boolean | Yes | To enable or disable Airways Bills Branding | - |
cod
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| cod_amount | double | Yes | Cash on Delivery amount | - |
| cod_currency_code | string | Yes | Currency code for COD transaction | Example: "MYR" |
Items
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| content | string | Yes | Description of the content | - |
| weight | double(8,2) | Yes | Weight of the item | in KG |
| height | double(8,2) | Yes | Height of the item | in CM |
| length | double(8,2) | Yes | Length of the item | in CM |
| width | double(8,2) | Yes | Width of the item | in CM |
| currency_code | string(3) | Yes | The currency code of the item value | Example: "MYR" |
| value | double(8,2) | Yes | Value of the item | - |
| quantity | int | Yes | The item quantity | - |
Sumbit Order Response
Successful Response Example
{
"status_code": 200,
"message": "2 requests success, 0 request error.",
"data": [
{
"order_details": {
"order_number": "EI-2601-U8FZW",
"account_id": 8583757
},
"pricing_breakdown": {
"currency_code": "MYR",
"total_order_amount": "23.52",
"total_paid_amount": "23.52",
"total_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"shipments": [
{
"status": "success",
"shipment_number": "ES-2601-K8S32",
"courier_service": null,
"courier": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Aramex.jpg",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"pricing_breakdown": {
"currency_code": "MYR",
"total_paid_amount": "10.25",
"shipment_price": "9.80",
"shipment_tax_amount": "0.00",
"total_features_price": "0.45",
"total_features_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas",
"subdivision_code": "MY-07",
"postcode": "10150",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1163042981",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"postcode": "11950",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 2
}
],
"features": {
"cod": null,
"insurance_purchase": [
{
"service_name": "Insure Plus",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
},
{
"service_name": "Basic Coverage",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
}
],
"shipment_tracking_whatsapp": {
"message": "Hey there! Your order from John Doe is ready to be collected for delivery soon!\n\nTracking no: null",
"phone_country_code": "+60",
"phone_number": "1163042981",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_sms": {
"message": "Your order from John Doe is ready & trackable once courier scans in. Track at EasyParcel with [Placeholder Trackin..] -Powered by EasyParcel",
"phone_country_code": "+60",
"phone_number": "1163042981",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_email": {
"email": "test@easyparcel.com",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.05",
"tax_amount": "0.00"
},
"shipment_awb_branding": null
}
},
{
"status": "success",
"shipment_number": "ES-2601-XV7UN",
"courier_service": null,
"courier": "DHL eCommerce",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/DHLeC.jpg",
"awb_number": "7227014253232636",
"awb_url": "https://app.easyparcel.com/portal/v2/public/label/ES-2601-XV7UN/3941082?format=A4",
"tracking_url": "https://app.easyparcel.com/tools/easytrack/details?courier=DHLeC&awb=7227014253232636",
"weight": 4,
"height": 30,
"length": 40,
"width": 20,
"pricing_breakdown": {
"currency_code": "MYR",
"total_paid_amount": "13.27",
"shipment_price": "13.02",
"shipment_tax_amount": "0.00",
"total_features_price": "0.25",
"total_features_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas",
"subdivision_code": "MY-07",
"postcode": "10150",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1163042981",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"postcode": "11950",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics",
"weight": 1,
"height": 30,
"length": 40,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 10,
"length": 20,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1
}
],
"features": {
"cod": null,
"insurance_purchase": [
{
"service_name": "Insure Plus",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
},
{
"service_name": "Basic Coverage",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
}
],
"shipment_tracking_whatsapp": {
"message": "Hey there! Your order from [Sender's Name] is ready to be collected for delivery soon!\n\nTracking no: [Tracking No.]",
"phone_country_code": "+60",
"phone_number": "1163042981",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_sms": null,
"shipment_tracking_email": {
"email": "test@easyparcel.com",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.05",
"tax_amount": "0.00"
},
"shipment_awb_branding": null
}
}
]
}
]
}
Successful Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of order results |
Order Details Object
| Parameter | Type | Description |
|---|---|---|
| order_details | object | Details about the order |
| pricing | object | Pricing information |
| shipments | array | Array of shipment details |
Order Details
| Parameter | Type | Description |
|---|---|---|
| order_number | string | Order number of the shipment batch |
| account_id | string | Account ID used for the shipment |
Pricing
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used for the shipment |
| total_amount | string | Total cost of all shipments |
| total_tax_amount | string | Total tax amount |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the shipment request |
| shipment_number | string | The unique number of the shipment |
| courier_service | string | Service type selected for shipment |
| courier | string | Name of the courier service |
| collection_date | string | Collection date of the parcel |
| awb_url | string | URL to access the airway bill |
| awb_number | string | The airway bill number |
| tracking_url | string | URL to track the parcel |
| weight | double | Weight of the shipment |
| height | double | Height of the shipment |
| length | double | Length of the shipment |
| width | double | Width of the shipment |
| pricing_breakdown | object | Detailed pricing breakdown |
| sender | object | Sender details |
| receiver | object | Receiver details |
| shipment_items | array | Items in the shipment |
| features | object | Enabled features details |
Pricing Breakdown
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used for the shipment |
| total_order_amount | string | Total cost of the shipment |
| shipment_price | string | Base price of the shipment |
| total_tax_amount | string | Tax amount |
| total_features_price | string | Total price for additional features |
| coupon_redeemed | string | Total amonut deducted using coupon_redeemed |
Features
| Parameter | Type | Description |
|---|---|---|
| cod | object | Cash on Delivery details (if enabled) |
| shipment_tracking_whatsapp | object | WhatsApp tracking details (if enabled) |
| shipment_tracking_sms | object | SMS tracking details (if enabled) |
| shipment_tracking_email | object | Email tracking details (if enabled) |
Error Response
For failed requests, the response includes error details:
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code indicating error |
| message | string | Error summary message |
| data | array | Array of shipment request details |
| errors | array | List of specific error messages |
Error Response Example
{
"status_code": 200,
"message": "1 request success, 1 request error.",
"data": [
{
"order_details": {
"order_number": "EI-2601-CS99V",
"account_id": 8583757
},
"pricing_breakdown": {
"currency_code": "MYR",
"total_order_amount": "12.55",
"total_paid_amount": "12.55",
"total_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"shipments": [
{
"status": "success",
"shipment_number": "ES-2601-U2W24",
"courier_service": null,
"courier": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Aramex.jpg",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"pricing_breakdown": {
"currency_code": "MYR",
"total_paid_amount": "12.55",
"shipment_price": "12.10",
"shipment_tax_amount": "0.00",
"total_features_price": "0.45",
"total_features_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas",
"subdivision_code": "MY-07",
"postcode": "10150",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1163042981",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"postcode": "11950",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 1
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 5,
"length": 5,
"width": 5,
"currency_code": "MYR",
"value": 50,
"quantity": 2
}
],
"features": {
"cod": null,
"insurance_purchase": [
{
"service_name": "Insure Plus",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
},
{
"service_name": "Basic Coverage",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
}
],
"shipment_tracking_whatsapp": {
"message": "Hey there! Your order from John Doe is ready to be collected for delivery soon!\n\nTracking no: null",
"phone_country_code": "+60",
"phone_number": "1126760658",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_sms": {
"message": "Your order from John Doe is ready & trackable once courier scans in. Track at EasyParcel with [Placeholder Trackin..] -Powered by EasyParcel",
"phone_country_code": "+60",
"phone_number": "1163042981",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_email": {
"email": "test@easyparcel.com",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.05",
"tax_amount": "0.00"
},
"shipment_awb_branding": null
}
},
{
"status": "error",
"collection_date": "",
"weight": "",
"height": "",
"length": "",
"width": "",
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1126760658",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "",
"subdivision_code": "",
"postcode": "10150",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1163642281",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "test@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "",
"subdivision_code": "",
"postcode": "",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics",
"weight": 0.5,
"height": 30,
"length": 40,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 1,
"insurance_purchase": null
},
{
"content": "Electronics 2",
"weight": 0.5,
"height": 10,
"length": 20,
"width": 20,
"currency_code": "MYR",
"value": 50,
"quantity": 2,
"insurance_purchase": null
}
],
"features": {
"cod": false,
"shipment_tracking_whatsapp": false,
"shipment_tracking_sms": false,
"shipment_tracking_email": false
},
"errors": [
"The receiver postcode field is required "
]
}
]
}
]
}
Shipment Listing
This endpoint allows users to retrieve a list of shipments with optional filtering parameters. Results are sorted by the latest shipments first.
HTTP Request (Listing)
POST https://api.easyparcel.com/open_api/2025-09/shipment/list
Pagination
This API uses cursor-based pagination with the before_shipment_number parameter. To retrieve the next page of results:
- Make your initial request with desired filters and
limit - Note the
shipment_numberof the last shipment in the response - Use that shipment number as
before_shipment_numberin your next request to get older shipments
Since results are sorted newest first, each subsequent request returns the next set of older shipments.
Request Sample
{
"limit": 3,
"before_shipment_number": "ES-2601-K8S32",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Note: You can submit a request without any filters, but the maximum limit is 250 shipments per API call. Results are sorted with the latest shipments first.
Main Structure
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| limit | int | No | Maximum number of results to return | Default: 10, Maximum: 250 |
| before_shipment_number | string | No | Get shipments before this shipment number | For pagination purposes |
| shipment_status_code | string | No | Filter by shipment status code | Example: "7" for "Schedule In Arrangement" |
| date_from | date | No | Start date for filtering shipments | Format: YYYY-MM-DD |
| date_to | date | No | End date for filtering shipments | Format: YYYY-MM-DD |
Returned Parameters
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"shipment_number": "ES-2504-X2KV5",
"awb_number": "960301021838937",
"awb_url": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/courier/consignment_note/49854776-1dda-4c4b-9bad-f66157e8f6b4.pdf",
"tracking_url": "https://app.easyparcel.com/tools/easytrack/details?courier=City-Link Express&awb=960301021838937",
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-30 00:00:00",
"courier": {
"service_type": "City-Link Express (Drop-Off)",
"courier_id": "EP-CR0D9",
"service_id": "EP-CS0D9",
"courier_name": "City-Link Express (M) Sdn. Bhd.",
"courier_short_name": "City-Link Express",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "Afiq",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"address1": "No 4",
"subdivision_code": "MY-02",
"postal_code": "06000",
"country": "MY"
},
"receiver_details": {
"name": "Afiq Receiver",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"subdivision_code": "MY-07",
"postal_code": "11900",
"country": "MY"
},
"pricing": {
"currency_code": "MYR",
"price": 5.65
}
},
{
"shipment_number": "ES-2504-2AE3R",
"awb_number": "960301021837659",
"awb_url": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/courier/consignment_note/17306a0f-f6e9-40ea-9957-c1d1e53d7692.pdf",
"tracking_url": "https://app.easyparcel.com/tools/easytrack/details?courier=City-Link Express&awb=960301021837659",
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-28 00:00:00",
"courier": {
"service_type": "City-Link Express (Drop-Off)",
"courier_id": "EP-CR0D9",
"service_id": "EP-CS0D9",
"courier_name": "City-Link Express (M) Sdn. Bhd.",
"courier_short_name": "City-Link Express",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "test afiq kedah",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"address1": "taman suria 5",
"subdivision_code": "MY-02",
"postal_code": "06000",
"country": "MY"
},
"receiver_details": {
"name": "Test afiq penang",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"subdivision_code": "MY-07",
"postal_code": "11900",
"country": "MY"
},
"pricing": {
"currency_code": "MYR",
"price": 5.65
}
},
{
"shipment_number": "ES-2504-QBURU",
"awb_number": "960301021837651",
"awb_url": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/courier/consignment_note/ca605e9f-5a24-47cb-a6cb-f1e9590de3d5.pdf",
"tracking_url": "https://app.easyparcel.com/tools/easytrack/details?courier=City-Link Express&awb=960301021837651",
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-29 00:00:00",
"courier": {
"service_type": "City-Link Express (Drop-Off)",
"courier_id": "EP-CR0D9",
"service_id": "EP-CS0D9",
"courier_name": "City-Link Express (M) Sdn. Bhd.",
"courier_short_name": "City-Link Express",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "test afiq kedah",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"address1": "taman suria 5",
"subdivision_code": "MY-02",
"postal_code": "06000",
"country": "MY"
},
"receiver_details": {
"name": "Test afiq penang",
"email": "afiq@easyparcel.com",
"contact": "MY124651303",
"alternative_contact": 0,
"subdivision_code": "MY-07",
"postal_code": "11900",
"country": "MY"
},
"pricing": {
"currency_code": "MYR",
"price": 5.65
}
}
],
"pagination": {
"next_page_token": "eyJsYXN0X2lkIjoyNzE0MywiZmlsdGVycyI6eyJ0cmFja2luZ19zdGF0dXMiOiI3IiwiZGF0ZV9mcm9tIjoiMjAyNS0wNC0wMSAwMDowMDowMCIsImRhdGVfdG8iOiIyMDI1LTA0LTIzIDIzOjU5OjU5In19",
"next_shipment_number": "ES-2504-QBURU",
"has_more": true,
"limit": 3,
"filter_applied": {
"tracking_status": "7",
"date_from": "2025-04-01 00:00:00",
"date_to": "2025-04-23 23:59:59",
"tracking_status_code": "7"
}
}
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of shipment objects |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| shipment_number | string | Unique shipment identifier |
| awb | string | Airway bill number (null if not assigned) |
| shipment_status_code | int | Status code of the shipment |
| shipment_status | string | Human-readable shipment status |
| coll_date | string | Collection date and time |
| courier | object | Courier information |
| sender_details | object | Sender information |
| receiver_details | object | Receiver information |
| pricing | object | Pricing information |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| service_type | string | Type of courier service |
| courier_id | string | Unique identifier for the courier |
| service_id | string | Unique identifier for the service |
| courier_name | string | Full name of the courier company |
| courier_short_name | string | Short name of the courier company |
| courier_logo | string | URL to the courier logo image |
Sender Details Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the sender |
| string | Email address of the sender | |
| contact | string | Contact number with country code |
| alternative_contact | string/int | Alternative contact number (0 if none) |
| address1 | string | First line of the sender's address |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
Receiver Details Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the receiver |
| string | Email address of the receiver | |
| contact | string | Contact number with country code |
| alternative_contact | string/int | Alternative contact number (0 if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
Pricing Object
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency code for the price |
| price | double | Price of the shipment |
Common Status Codes
| Status Code | Description |
|---|---|
| 200 | Successful request |
| 400 | Bad request (missing or invalid parameters) |
| 401 | Unauthorized (invalid authentication) |
| 404 | Not found (no shipments matching the criteria) |
| 500 | Server error |
Usage Notes (Listing)
- For pagination, use the
before_shipment_numberparameter with the last shipment number from the previous request. - Date filters (
date_fromanddate_to) filter by shipment collection date. - Results are always sorted by newest first.
- When no filters are applied, the API returns the most recent shipments up to the specified limit.
Shipment Details
This endpoint allows users to retrieve detailed information about a specific shipment using its shipment number.
HTTP Request (Detail)
POST https://api.easyparcel.com/open_api/2025-09/shipment/details
Shipment Details Request
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| shipment_number | string | Yes | Shipment number to query | Format: ES-YYMM-XXXXX |
Request Sample
{
"shipment_number": "ES-2601-K8S32"
}
Shipment Details Return
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"shipment_number": "ES-2601-K8S32",
"order_number": "EI-2601-U8FZW",
"shipment_details": {
"weight": 1.5,
"height": 5,
"length": 5,
"width": 5,
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"parcels_value": "100",
"insurance_label": "basic",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"coll_date": "2025-05-19 00:00:00"
},
"parcel_content": [
{
"content": "Electronics",
"weight": "0.50000",
"height": 5,
"length": 5,
"width": 5,
"value": 50,
"currency_code": "MYR"
},
{
"content": "Electronics 2",
"weight": "0.50000",
"height": 5,
"length": 5,
"width": 5,
"value": 50,
"currency_code": "MYR"
}
],
"courier": {
"courier_name": "Aramex",
"service_id": "EP-CS0AP",
"courier_id": "EP-CR0AP",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/aramex.jpg",
"service_types": "Aramex (Pick Up)"
},
"sender": {
"name": "John Doe",
"company_name": "ABC Corp",
"email": "test@easyparcel.com",
"contact": "+601126760658",
"alternative_contact": null,
"subdivision_code": "MY-07",
"postal_code": "10150",
"country": "MY",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas"
},
"receiver": {
"name": "Jane Smith",
"company_name": "XYZ Inc",
"email": "test@easyparcel.com",
"contact": "+601163042981",
"alternative_contact": null,
"subdivision_code": "MY-07",
"postal_code": "11950",
"country": "MY",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas"
},
"pricing": {
"currency_code": "MYR",
"total_price": "0.00",
"shipment_price": "9.80",
"tax_price": "0.00",
"sms_notification": "0.00",
"email_notification": "0.00",
"whatsapp_notification": "0.00",
"awb_branding": null,
"insurance": null,
"ddp": null
}
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array containing the shipment details |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| shipment_number | string | Unique shipment identifier |
| order_number | string | Order number associated with shipment |
| shipment_details | object | Detailed shipment information |
| parcel_content | array | List of items in the shipment |
| courier | object | Courier service information |
| sender | object | Sender information |
| receiver | object | Receiver information |
| pricing | object | Detailed pricing breakdown |
Shipment Details Object
| Parameter | Type | Description |
|---|---|---|
| weight | double | Total weight of the shipment |
| height | double | Height of the shipment |
| length | double | Length of the shipment |
| width | double | Width of the shipment |
| shipment_status_code | int | Status code of the shipment |
| shipment_status | string | Human-readable shipment status |
| parcels_value | string | Total value of items in the shipment |
| insurance_label | string | Insurance information (null if not insured) |
| awb_number | string | Airway bill number (null if not assigned) |
| tracking_url | string | URL to track the shipment |
| awb_url | string | URL to access the airway bill |
| coll_date | string | Collection date and time |
Parcel Content Object
| Parameter | Type | Description |
|---|---|---|
| content | string | Description of the item |
| weight | string | Weight of the item |
| height | int | Height of the item |
| length | int | Length of the item |
| width | int | Width of the item |
| value | double | Monetary value of the item |
| currency_code | string | Currency code for the item value |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| courier_name | string | Full name of the courier company |
| service_id | string | Unique identifier for the service |
| courier_id | string | Unique identifier for the courier |
| courier_logo | string | URL to the courier logo image |
| service_types | string | Type of courier service |
Sender Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the sender |
| company_name | string | Company name of the sender |
| string | Email address of the sender | |
| contact | string | Contact number with country code |
| alternative_contact | string | Alternative contact number (null if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
| address1 | string | First line of the sender's address |
| address2 | string | Second line of the sender's address |
| city | string | City/town of the sender |
Receiver Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the receiver |
| company_name | string | Company name of the receiver |
| string | Email address of the receiver | |
| contact | string | Contact number with country code |
| alternative_contact | string | Alternative contact number (null if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
| address1 | string | First line of the receiver's address |
| address2 | string | Second line of the receiver's address |
| city | string | City/town of the receiver |
Pricing Object
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency code for all pricing |
| total_price | string | Total price of the shipment |
| shipment_price | string | Base shipping cost |
| tax_price | string | Tax amount |
| sms_notification | string | Price for SMS notification (null if not enabled) |
| email_notification | string | Price for email notification (null if not enabled) |
| whatsapp_notification | string | Price for WhatsApp notification (null if not enabled) |
| awb_branding | string | Price for AWB branding (null if not enabled) |
| insurance | string | Price for insurance (null if not purchased) |
| ddp | string | Delivered Duty Paid fee (null if not applicable) |
Error Response
If the shipment is not found or the request is invalid, the API will return an error response:
{
"status_code": 404,
"message": "No Order with shipment_number ES-2601-K8S3 found from this account",
"data": []
}
Usage Notes (Detail)
- This endpoint retrieves comprehensive information about a single shipment.
- The shipment number must be in the format ES-YYMM-XXXXX (e.g., ES-2504-3WYYP).
- Values for various fields like awb_number, insurance_label, etc. may be null if they aren't applicable to the shipment's current status.
- Pricing details provide a complete breakdown of all charges associated with the shipment.
- The tracking_url can be used to provide tracking information to customers.
Cancel Shipments
This endpoint allows users to cancel one or more shipments. Users can provide a list of shipment numbers along with cancellation remarks.
HTTP Request (Cancel)
POST https://api.easyparcel.com/open_api/2025-09/shipment/cancel
Cancel Request Parameters
Request Sample
{
"cancel_list": [
{
"shipment_number": "ES-2601-K8S32",
"remark": "test"
},
{
"shipment_number": "ES-2601-XV7UN",
"remark": "test"
}
]
}
Main Structure
| Parameter | Type | Required | Description |
|---|---|---|---|
| cancel_list | array | Yes | List of shipments to cancel |
Cancel Item Object
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| shipment_number | string | Yes | Shipment number to cancel | Format: ES-YYMM-XXXXX |
| remark | string | Yes | Reason for cancellation | - |
Cancel Return Parameters
Successful Response Example
{
"status_code": 200,
"message": "2 requests success, 0 request error.",
"data": [
{
"status": "success",
"message": "Shipment Cancelled",
"shipment_number": "ES-2601-K8S32"
},
{
"status": "success",
"message": "Shipment Cancelled",
"shipment_number": "ES-2601-XV7UN"
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Summary message (e.g., "2 requests success, 0 request error.") |
| data | array | Array of cancellation results |
Cancellation Result Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the cancellation request ("success" or "error") |
| message | string | Detailed message about the cancellation result |
| shipment_number | string | The shipment number that was processed |
Error Response Example
{
"status_code": 200,
"message": "0 requests success, 3 request error.",
"data": [
{
"status": "error",
"message": "Shipment Already Cancelled, Cannot Cancel Again",
"shipment_number": "ES-2601-K8S32"
},
{
"status": "error",
"message": "The shipment cancellation period is over (7 days from collection date: 2025-05-19)",
"shipment_number": "ES-2601-QTG7S"
},
{
"status": "error",
"message": "Shipment Not Found",
"shipment_number": "ES-2504-GPC39"
}
]
}
Usage Notes (Cancellation)
- You can cancel multiple shipments in a single request by including them in the
cancel_listarray. - Only shipments that have not yet been processed by the courier can be cancelled.
- Each shipment in the
cancel_listwill be processed independently - some may succeed while others fail. - A successful response (
status_code: 200) does not guarantee all shipments were cancelled. Always check individual status values in the data array. - Cancellation remarks are mandatory and should provide a reason for the cancellation.
- The API returns a 200 status code even when all cancellations fail, so always check the message and data fields.
Tracking Status Feature
The tracking status feature allows customers to retrieve real-time tracking information for their shipments using AWB (Air Waybill) numbers. This helps users monitor the delivery progress and current status of their parcels.
Retrieving Tracking Status
Customers can retrieve tracking information for one or multiple shipments using the following endpoint:
HTTP Request (Tracking Status)
POST https://api.easyparcel.com/open_api/2025-09/shipment/tracking_status
This endpoint returns detailed tracking information including the current status, historical events, and location data for each requested shipment.
Tracking Status Request
Submitting AWB Numbers to Get Tracking Information
You can submit multiple AWB numbers in a single request to retrieve tracking status for multiple shipments simultaneously.
Sample Tracking Status Request:
{
"awb_numbers": ["7227014253232636", "960301021838937", "960301021837659"]
}
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| awb_numbers | array | Yes | List of AWB numbers to track (max 100 per request) |
Tracking Status Response
Tracking Status API - Response Parameters
Sample Response for Tracking Status
{
"status_code": 200,
"message": "3 requests success, 0 request error.",
"data": {
"results": [
{
"status": "success",
"awb_number": "7227014253232636",
"shipment_number": "ES-2601-XV7UN",
"order_number": "EI-2601-U8FZW",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Schedule In Arrangement",
"latest_event_date": "2026-01-23T04:28:52.494Z",
"status_log": [
{
"event_date": "2026-01-23 12:29:47",
"shipment_status_code": 7,
"tracking_status": "Shipment data received - Awaiting Parcel Handover to DHL",
"location": "Kuala Lumpur Hub, Kuala Lumpur, MY"
},
{
"event_date": "2026-01-23 12:28:52",
"shipment_status_code": 7,
"tracking_status": "Data Submitted - Awaiting Parcel Handover to DHL",
"location": "BAYAN BARU, PENANG,, PIN, MY"
},
{
"event_date": "2026-01-23T04:28:52.494Z",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
}
]
},
{
"status": "success",
"awb_number": "960301021838937",
"shipment_number": "ES-2504-X2KV5",
"order_number": "EI-2504-SKMTH",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Schedule In Arrangement",
"latest_event_date": "2025-04-23 08:13:12",
"status_log": [
{
"event_date": "2025-04-23 16:13:00",
"shipment_status_code": 7,
"tracking_status": "Shipment information sent to City-Link",
"location": null
},
{
"event_date": "2025-04-23 08:13:12",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
}
]
},
{
"status": "success",
"awb_number": "960301021837659",
"shipment_number": "ES-2504-2AE3R",
"order_number": "EI-2504-WUHYR",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Shipment information sent to City-Link",
"latest_event_date": "2025-04-23 10:46:00",
"status_log": [
{
"event_date": "2025-04-23 02:46:36",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
},
{
"event_date": "2025-04-23 10:46:00",
"shipment_status_code": 7,
"tracking_status": "Shipment information sent to City-Link",
"location": null
}
]
}
]
}
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| request_id | string | Unique identifier for the API request |
| message | string | Summary of the response (e.g., number of successful/failed requests) |
| data | object | Container for tracking results |
data Object
| Parameter | Type | Description |
|---|---|---|
| results | array | List of tracking result objects for each AWB |
result Object (Inside results array)
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the tracking request ("success" or "not_found") |
| awb_number | string | Air Waybill number for the shipment |
| shipment_number | string | EasyParcel shipment reference number (only for successful requests) |
| order_number | string | EasyParcel order reference number (only for successful requests) |
| latest_shipment_status_code | int | Numeric code representing the current shipment status (only for successful requests) |
| latest_tracking_status | string | Human-readable description of the current status (only for successful requests) |
| latest_event_date | string | Date and time of the most recent tracking event (YYYY-MM-DD HH:MM:SS) (only for successful requests) |
| status_log | array | Chronological list of all tracking events for this shipment (only for successful requests) |
| message | string | Error message explaining why the request failed (only for failed requests) |
status_log Object (Inside status_log array)
| Parameter | Type | Description |
|---|---|---|
| event_date | string | Date and time when this event occurred (YYYY-MM-DD HH:MM:SS) |
| shipment_status_code | int | Numeric code representing the shipment status at this event |
| tracking_status | string | Human-readable description of the status at this event |
| location | string | Location where the event occurred (null if not available) |
Shipment Status Codes
Below are common shipment status codes you may encounter:
| Status Code | Description |
|---|---|
| 1 | Order Created |
| 2 | Payment Confirmed |
| 3 | Ready for Collection |
| 4 | Item Collected |
| 5 | In Transit to Hub |
| 6 | Processing at Hub |
| 7 | Schedule In Arrangement |
| 8 | Out for Delivery |
| 9 | Delivered |
| 10 | Delivery Failed |
| 11 | Return to Sender |
Note: Status codes may vary by courier and region. Refer to the API response for the most accurate status description.
Usage Notes (Tracking)
- Batch Tracking: You can track up to 100 AWB numbers in a single API request for efficiency.
- Real-time Updates: Tracking information is updated in near real-time as events are recorded by the courier.
- Status Log: The
status_logarray provides a complete history of all tracking events in chronological order. - Error Handling: If an AWB number is invalid or not found, the corresponding result object will have
status: "not_found"with a descriptive message field. - Date Format: All dates and times are returned in
YYYY-MM-DD HH:MM:SSformat in UTC timezone.
Example Use Cases
Single Shipment Tracking
{
"awb_numbers": ["7227014253232636"]
}
Multiple Shipment Tracking
{
"awb_numbers": [
"7227014253232636",
"960301021838937",
"960301021837659",
"1234567890"]
}
Error Response Example
If one or more AWB numbers are invalid:
{
"status_code": 200,
"request_id": "1769761472947.b7a9d539-083a-48d7-8974-0fd6f13baa72",
"message": "3 requests success, 1 request error.",
"data": {
"results": [
{
"status": "success",
"awb_number": "7227014253232636",
"shipment_number": "ES-2601-XV7UN",
"order_number": "EI-2601-U8FZW",
"latest_shipment_status_code": 8,
"latest_tracking_status": "Cancelled",
"latest_event_date": "2026-01-30 10:04:18",
"status_log": [
{
"event_date": "2026-01-23 12:29:47",
"shipment_status_code": 7,
"tracking_status": "Shipment data received - Awaiting Parcel Handover to DHL",
"location": "Kuala Lumpur Hub, Kuala Lumpur, MY"
},
{
"event_date": "2026-01-23 12:28:52",
"shipment_status_code": 7,
"tracking_status": "Data Submitted - Awaiting Parcel Handover to DHL",
"location": "BAYAN BARU, PENANG,, PIN, MY"
},
{
"event_date": "2026-01-23T04:28:52.494Z",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
},
{
"event_date": "2026-01-30 10:04:18",
"shipment_status_code": 8,
"tracking_status": "Cancelled",
"location": "Kuala Lumpur Hub, Kuala Lumpur, MY"
}
]
},
{
"status": "success",
"awb_number": "960301021838937",
"shipment_number": "ES-2504-X2KV5",
"order_number": "EI-2504-SKMTH",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Schedule In Arrangement",
"latest_event_date": "2025-04-23 08:13:12",
"status_log": [
{
"event_date": "2025-04-23 16:13:00",
"shipment_status_code": 7,
"tracking_status": "Shipment information sent to City-Link",
"location": null
},
{
"event_date": "2025-04-23 08:13:12",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
}
]
},
{
"status": "success",
"awb_number": "960301021837659",
"shipment_number": "ES-2504-2AE3R",
"order_number": "EI-2504-WUHYR",
"latest_shipment_status_code": 7,
"latest_tracking_status": "Schedule In Arrangement",
"latest_event_date": "2025-04-23 02:46:36",
"status_log": [
{
"event_date": "2025-04-23 10:46:00",
"shipment_status_code": 7,
"tracking_status": "Shipment information sent to City-Link",
"location": null
},
{
"event_date": "2025-04-23 02:46:36",
"shipment_status_code": 7,
"tracking_status": "Schedule In Arrangement",
"location": null
}
]
},
{
"awb_number": "1234567890",
"status": "not_found",
"message": "AWB number not found"
}
]
}
}
Insurance Quotation Feature
The insurance quotation feature allows customers to retrieve pricing information for shipment insurance coverage. This helps users understand the cost of insuring their valuable parcels and make informed decisions about protecting their shipments against loss or damage.
Retrieving Insurance Quotations
Customers can retrieve insurance pricing for one or multiple shipments using the following endpoint:
HTTP Request (Insurance Quotation)
POST https://api.easyparcel.com/open_api/2025-09/insurance_quotations
This endpoint returns detailed insurance pricing based on shipment details including courier, origin, destination, weight, and item values.
Insurance Quotation Request
Submitting Shipment Details to Get Insurance Pricing
You can submit multiple shipment scenarios in a single request to retrieve insurance quotations for batch processing.
Sample Insurance Quotation Request:
{
"list": [
{
"courier_id": "EP-CR0AP",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
{
"courier_id": "EP-CR0AW",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
}
]
}
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| list | array | Yes | Array of shipment objects to get insurance quotes for |
Shipment Object (Inside list array)
| Parameter | Type | Required | Description |
|---|---|---|---|
| courier_id | string | Yes | EasyParcel courier service ID (e.g., "EP-CR0AW") |
| currency_code | string | Yes | Currency code for the quotation (e.g., "MYR") |
| from_postcode | string | Yes | Origin postcode |
| from_country | string | Yes | Origin country code (ISO 3166-1 alpha-2, e.g., "MY") |
| to_postcode | string | Yes | Destination postcode |
| to_country | string | Yes | Destination country code (ISO 3166-1 alpha-2) |
| shipment_weight | number | Yes | Total shipment weight in kilograms |
| shipment_item | array | Yes | Array of item objects to be insured |
Item Object (Inside shipment_item array)
| Parameter | Type | Required | Description |
|---|---|---|---|
| value | number | Yes | Declared value of the item |
| quantity | int | Yes | Quantity of items |
| currency_code | string | Yes | Currency code for the item value (e.g., "MYR") |
Insurance Quotation Response
Insurance Quotation API - Response Parameters
Sample Response for Insurance Quotations
{
"status_code": 200,
"message": "2 requests success, 0 request error.",
"data": [
{
"status": "success",
"input": {
"courier_id": "EP-CR0AP",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
"insurance_quotations": [
{
"insurance_service_id": "EP-IR0D",
"insurance_service_name": "EasyCover",
"insurance_cover_notice": "for lost",
"currency_code": "MYR",
"charge_amount": 7.5,
"pricing": {
"currency_code": "MYR",
"charge_amount": 7.5,
"base_fee": 0,
"max_item_value": null,
"min_item_value": "200.01",
"percentage_rate": "0.025",
"max_item_value_coverage": 10000
}
}
]
},
{
"status": "success",
"input": {
"courier_id": "EP-CR0AW",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
"insurance_quotations": [
{
"insurance_service_id": "EP-IR0D",
"insurance_service_name": "EasyCover",
"insurance_cover_notice": "for lost",
"currency_code": "MYR",
"charge_amount": 75,
"pricing": {
"currency_code": "MYR",
"charge_amount": 75,
"base_fee": 0,
"max_item_value": null,
"min_item_value": "200.01",
"percentage_rate": "0.025",
"max_item_value_coverage": 10000
}
}
]
}
]
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| request_id | string | Unique identifier for the API request |
| message | string | Summary of the response (e.g., number of successful/failed requests) |
| data | array | Array of quotation result objects |
Quotation Result Object (Inside data array)
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the quotation request ("success" or "error") |
| input | object | Echo of the input parameters sent in the request |
| insurance_quotations | array | Array of available insurance options for this shipment |
Insurance Quotation Object (Inside insurance_quotations array)
| Parameter | Type | Description |
|---|---|---|
| insurance_service_id | string | Unique identifier for the insurance service |
| insurance_service_name | string | Display name of the insurance service (e.g., "EasyCover") |
| insurance_cover_notice | string | Coverage details or notice (e.g., "for lost") |
| currency_code | string | Currency code for the insurance charge |
| charge_amount | number | Total insurance charge amount |
| pricing | object | Detailed pricing breakdown for the insurance |
Pricing Object (Inside insurance_quotations)
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency code for pricing |
| charge_amount | number | Calculated insurance charge based on item value |
| base_fee | number | Base fee for insurance (if applicable) |
| max_item_value | number | Maximum item value for this pricing tier (null if no max) |
| min_item_value | string | Minimum item value required for this insurance tier |
| percentage_rate | string | Percentage rate applied to item value (e.g., "0.025" = 2.5%) |
| max_item_value_coverage | number | Maximum coverage amount available for items |
Understanding Insurance Pricing
Insurance charges are typically calculated based on:
- Base Fee: A flat fee that applies regardless of item value (if applicable)
- Percentage Rate: A percentage of the declared item value
- Value Tiers: Different rates may apply based on item value ranges
Example Calculation:
For an item valued at MYR 3,000: - Base Fee: MYR 0 - Percentage Rate: 2.5% (0.025) - Calculation: (3,000 × 0.025) + 0 = MYR 75
Usage Notes (Insurance Quotation)
- Batch Quotations: You can request insurance quotes for multiple shipments in a single API call for efficiency.
- Currency Consistency: Ensure the currency codes match across shipment items and quotation requests.
- Coverage Limits: Note the
max_item_value_coverageto understand the maximum insured amount available. - Minimum Values: Items below the
min_item_valuethreshold may not be eligible for insurance or may use different pricing. - Multiple Options: Some shipments may have multiple insurance service options available with different pricing structures.
Example Use Cases
Single Shipment Quotation
{
"list": [
{
"courier_id": "EP-CR0AP",
"currency_code": "MYR",
"from_postcode": "50000",
"from_country": "MY",
"to_postcode": "10450",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 1500,
"quantity": 1,
"currency_code": "MYR"
}
]
}
]
}
Multiple Items in One Shipment
{
"list": [
{
"courier_id": "EP-CR0AW",
"currency_code": "MYR",
"from_postcode": "11900",
"from_country": "MY",
"to_postcode": "11900",
"to_country": "MY",
"shipment_weight": 3,
"shipment_item": [
{
"value": 500,
"quantity": 2,
"currency_code": "MYR"
},
{
"value": 800,
"quantity": 1,
"currency_code": "MYR"
}
]
}
]
}
International Shipment
{
"list": [
{
"courier_id": "EP-CR0D9",
"currency_code": "MYR",
"from_postcode": "11900",
"from_country": "MY",
"to_postcode": "10001",
"to_country": "US",
"shipment_weight": 2,
"shipment_item": [
{
"value": 5000,
"quantity": 1,
"currency_code": "MYR"
}
]
}
]
}
Applying Insurance to Shipments
Once you receive an insurance quotation, you can apply the insurance to your shipment by including the insurance_service_id in your shipment submission request.
Example Insurance Application in Shipment Submission:
{
"shipment": [
{
"service_id": "EP-CS096",
"insurance_service_id": "EP-IR0D",
// ... other shipment details
}
]
}
Error Handling
If a quotation request fails, the response will include an error status:
{
"status_code": 200,
"message": "0 requests success, 2 request error.",
"data": [
{
"status": "error",
"input": {
"courier_id": "EP-CR0AP",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
"errors": [
"Insurance service not available for this request"
]
},
{
"status": "error",
"input": {
"courier_id": "",
"currency_code": "MYR",
"from_postcode": "10150",
"from_country": "MY",
"to_postcode": "11950",
"to_country": "MY",
"shipment_weight": 1.5,
"shipment_item": [
{
"value": 50,
"quantity": 3,
"currency_code": "MYR"
}
]
},
"errors": [
"The courier id field is required "
]
}
]
}
Couriers List
This endpoint allows users to retrieve a list of available courier services for a specific country.
HTTP Request (Courier List)
GET https://api.easyparcel.com/open_api/2025-09/courier/list
Courier List Request
Request Sample
{
"country_code": "MY"
}
Requested Parameters
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| country_code | string | Yes | Country code to filter by | Example: "MY" for Malaysia |
Courier List Response
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"courier_id": "EP-CR0AP",
"uuid": "01e1cad9-d20a-411f-8c71-a1b3ed722b3f",
"courier_name": "Aramex",
"short_name": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Aramex.jpg",
"country": "Malaysia"
},
{
"courier_id": "EP-CR0AW",
"uuid": "db129869-d2cd-474a-b3bf-9995a436ef85",
"courier_name": "DHL eCommerce",
"short_name": "DHLeC",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/DHLeC.jpg",
"country": "Malaysia"
},
{
"courier_id": "EP-CR0AM",
"uuid": "17bd49e0-f356-41d0-805e-2b6ee8e3d6cc",
"courier_name": "Poslaju National Courier",
"short_name": "Pos Laju",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Pos_Laju.jpg",
"country": "Malaysia"
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of available courier services |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| courier_id | string | Unique identifier for the courier |
| uuid | string | Universal unique identifier |
| courier_name | string | Full name of the courier company |
| short_name | string | Abbreviated name of the courier |
| courier_logo | string | URL to the courier's logo image |
| country | string | Country where the courier operates |
Error Response
If an invalid country code is provided, the API will return an error response:
{
"status_code": 400,
"message": "Invalid country code",
"data": []
}
Supported Country Codes
| Country Code | Country Name |
|---|---|
| MY | Malaysia |
| SG | Singapore |
Common Status Code
| Status Code | Description |
|---|---|
| 200 | Successful request |
| 400 | Bad request (invalid country code) |
| 401 | Unauthorized (invalid authentication) |
| 500 | Server error |
Usage Notes (Courier List)
- The
courier_idvalue returned by this endpoint is used in other API calls, such as when submitting a shipment order. - Courier availability may vary by country. Use the appropriate country code to get relevant results.
- The response includes full company names and shortened display names for each courier.
- Courier logos can be used in your application to display carrier branding.
- There may be multiple entries for the same courier company if they offer different types of services.
Courier Drop-off Points Feature
The courier drop-off points feature allows customers to retrieve a list of available drop-off locations where they can physically bring their parcels for shipment. This helps users find convenient locations near them to drop off their packages instead of scheduling a pickup.
Retrieving Drop-off Points
Customers can retrieve a list of available drop-off locations for a specific courier using the following endpoint:
HTTP Request (Drop-off Points)
POST https://api.easyparcel.com/open_api/2025-09/courier/get_courier_dropoff_points
This endpoint returns detailed information about drop-off locations including addresses, operating hours, and contact information based on the specified courier and location parameters.
Drop-off Points Request
Submitting Location Details to Get Available Drop-off Points
You can query drop-off points by providing courier and location information to find the nearest available locations.
Sample Drop-off Points Request:
{
"courier_id": "EP-CR0AP",
"country_code": "MY",
"postcode": "10150",
"city": "Lunas",
"state_code": "MY-07"
}
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| courier_id | string | Yes | EasyParcel courier service ID (e.g., "EP-CR0A") |
| country_code | string | Yes | Country code (ISO 3166-1 alpha-2, e.g., "MY") |
| postcode | string | Yes | Postcode/ZIP code of the search location |
| city | string | Yes | City name for the search location |
| state_code | string | Yes | State/subdivision code (ISO 3166-2 format, e.g., "MY-02") |
Drop-off Points Response
Drop-off Points API - Response Parameters
Sample Response for Drop-off Points
{
"status_code": 200,
"message": "Success",
"data": [
{
"point_id": "EP-CB0FF",
"name": "Pejabat Pos Besar Pulau Pinang",
"address_1": "Tingkat Bawah, Bangunan Tuanku Syed Putra",
"address_2": "Leboh Downing",
"address_3": "",
"address_4": "",
"postcode": "10670",
"city": "Pulau Pinang",
"state": "png",
"phone_number": "04-2619222",
"info": "",
"image": "",
"start_time": "08:00:00",
"end_time": "13:00:00"
},
{
"point_id": "EP-CB0F9",
"name": "Pos Malaysia Ayer Itam",
"address_1": "JKR 19",
"address_2": "Jalan Paya Terubung",
"address_3": "",
"address_4": "",
"postcode": "11500",
"city": "Ayer Itam",
"state": "png",
"phone_number": "04-8283226",
"info": "",
"image": "",
"start_time": "08:00:00",
"end_time": "13:00:00"
},
{
"point_id": "EP-CB0F5",
"name": "Pos Malaysia Balik Pulau",
"address_1": "JKR 2312",
"address_2": "Jalan Besar",
"address_3": "",
"address_4": "",
"postcode": "11000",
"city": "Balik Pulau",
"state": "png",
"phone_number": "04-8668204",
"info": "",
"image": "",
"start_time": "08:00:00",
"end_time": "13:00:00"
},
{
"point_id": "EP-CB0FG",
"name": "Pos Malaysia Batu Ferringghi",
"address_1": "JKR 2340",
"address_2": "Jalan Batu Ferringghi",
"address_3": "",
"address_4": "",
"postcode": "11100",
"city": "Batu Ferringghi",
"state": "png",
"phone_number": "04-8668204",
"info": "",
"image": "",
"start_time": "08:00:00",
"end_time": "13:00:00"
}
]
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| request_id | string | Unique identifier for the API request |
| message | string | Description of the response status |
| data | array | Array of drop-off point objects |
Drop-off Point Object (Inside data array)
| Parameter | Type | Description |
|---|---|---|
| point_id | string | Unique identifier for the drop-off point |
| name | string | Name of the drop-off location |
| address_1 | string | Primary address line |
| address_2 | string | Secondary address line (street name, building details) |
| address_3 | string | Additional address line (may be empty) |
| address_4 | string | Additional address line (may be empty) |
| postcode | string | Postcode of the drop-off location |
| city | string | City where the drop-off point is located |
| state | string | State/region code or abbreviation |
| phone_number | string | Contact phone number for the drop-off location |
| info | string | Additional information or notes about the location (may be empty) |
| image | string | URL to an image of the location (may be empty) |
| start_time | string | Opening time in HH:MM:SS format (24-hour) |
| end_time | string | Closing time in HH:MM:SS format (24-hour) |
Understanding Operating Hours
Drop-off points have specific operating hours when customers can drop off their parcels:
- start_time: The time when the location opens for drop-offs
- end_time: The time when the location closes for drop-offs
- Format: Times are provided in 24-hour format (HH:MM:SS)
Example:
start_time: "08:00:00" → Opens at 8:00 AM
end_time: "13:00:00" → Closes at 1:00 PM
Important: Ensure customers arrive before the closing time to successfully drop off their parcels. Some locations may have limited operating hours (e.g., morning only).
Usage Notes (Courier List)
- Location-based Search: Results are typically sorted by proximity to the specified postcode and city.
- Courier-specific: Each courier may have different drop-off locations. Always query with the specific courier ID you're using.
- Operating Hours: Always check the
start_timeandend_timeto inform customers of available drop-off windows. - Empty Fields: Some fields like
address_3,address_4,info, andimagemay be empty strings if not applicable. - Phone Contact: The
phone_numbercan be used to verify operating hours or get additional information about the location.
Example Use Cases
Finding Drop-off Points in Kuala Lumpur
{
"courier_id": "EP-CR0AP",
"country_code": "MY",
"postcode": "50000",
"city": "Kuala Lumpur",
"state_code": "MY-14"
}
Finding Drop-off Points in Penang
{
"courier_id": "EP-CR0AP",
"country_code": "MY",
"postcode": "10000",
"city": "George Town",
"state_code": "MY-07"
}
Different Courier Service
{
"courier_id": "EP-CR0AW",
"country_code": "MY",
"postcode": "80000",
"city": "Johor Bahru",
"state_code": "MY-01"
}
Displaying Drop-off Points to Customers
When presenting drop-off points to your users, consider displaying:
- Location Name - Clear identification of the drop-off point
- Full Address - Concatenate address lines for easy navigation
- Operating Hours - Display in user-friendly format (e.g., "8:00 AM - 1:00 PM")
- Distance - Calculate and show distance from user's location (if possible)
- Contact Number - Allow users to call for inquiries
- Map Integration - Use address/postcode to show location on a map
Display Example:
📍 Pejabat Pos Besar Pulau Pinang
Tingkat Bawah, Bangunan Tuanku Syed Putra
Leboh Downing, 10670 Pulau Pinang
⏰ Operating Hours: 8:00 AM - 1:00 PM
📞 Phone: 04-2619222
Applying Drop-off Points to Shipments
Once a customer selects a drop-off point, you can include the point_id in your shipment submission request to indicate the parcel will be dropped off at that location instead of being picked up.
Example Drop-off Point Application in Shipment Submission:
{
"shipment": [
{
"service_id": "EP-CS096",
"dropoff_point_id": "EP-CB0FF",
"collection_method": "dropoff",
// ... other shipment details
}
]
}
Note: Specific implementation may vary based on the shipment submission endpoint requirements.
Error Handling
No Drop-off Points Available
If no drop-off points are found for the specified location:
{
"status_code": 200,
"message": "No drop-off points found",
"data": []
}
Invalid Courier or Location
If the courier ID is invalid or doesn't service the specified location:
{
"status_code": 400,
"message": "Invalid courier ID or location not serviced",
"data": null
}
State Codes Reference (Malaysia)
Common Malaysian state codes (ISO 3166-2):
| State Code | State Name |
|---|---|
| MY-01 | Johor |
| MY-02 | Kedah |
| MY-03 | Kelantan |
| MY-04 | Malacca (Melaka) |
| MY-05 | Negeri Sembilan |
| MY-06 | Pahang |
| MY-07 | Penang (Pulau Pinang) |
| MY-08 | Perak |
| MY-09 | Perlis |
| MY-10 | Selangor |
| MY-11 | Terengganu |
| MY-12 | Sabah |
| MY-13 | Sarawak |
| MY-14 | Kuala Lumpur |
| MY-15 | Labuan |
| MY-16 | Putrajaya |
Best Practices for Courier List
- Cache Results: Consider caching drop-off point data for a reasonable period (e.g., 24 hours) as locations rarely change frequently.
- Sort by Distance: If possible, calculate distance from user's location and sort results accordingly for better UX.
- Show Operating Hours Prominently: Make sure users are aware of the operating hours before traveling to a drop-off point.
- Provide Alternatives: If the nearest drop-off point is far, consider offering pickup service as an alternative.
- Verify Before Departure: Suggest users call the drop-off location to confirm operating hours, especially on public holidays.
- Map Integration: Integrate with mapping services (Google Maps, Waze) to provide navigation directions.
- Filter by Time: Allow users to filter drop-off points based on current time and whether they're currently open.
OnDemand Shipping
OnDemand API Flow Overview
This document provides a visual representation of the different flows and processes available through the EasyParcel API.
OnDemand Workflow Diagram
OnDemand Quotation
OnDemand Quotation Overview
This feature enables users to obtain on-demand shipment quotations from all courier companies available on the EasyParcel platform. Users need to provide sender and receiver addresses and waypoint information to retrieve shipment quotations. The response includes available courier services, transportation type, pricing details, and optional add-on features.
HTTP Request (OnDemand Quotation)
POST https://api.easyparcel.com/open_api/2025-09/ondemand/quotations
OnDemand Quotation Request Parameters
Request Sample
{
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"type": "pickup"
},
{
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia",
"type": "dropoff"
}
]
}
Main Structure
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| schedule_pickup_date | string | No | Scheduled pickup date (YYYY-MM-DD) | - |
| schedule_pickup_time | string | No | Scheduled pickup time (HH:MM:SS) | - |
| timezone | string | No | Pickup timezone | - |
| waypoint | array | Yes | List of pickup and dropoff points | Minimum 2 required |
| waypoint[*].coordinates.latitude | numeric | Yes | Location latitude | - |
| waypoint[*].coordinates.longitude | numeric | Yes | Location longitude | - |
| waypoint[*].address | string | No | Full address of the location | - |
| waypoint[*].type | string | Yes | Either pickup or dropoff |
- |
OnDemand Quotation Response Parameters
Sample Response
Refer to the full JSON response you provided in your message for all details on courier quotations including Lalamove and PandaGo examples with their respective vehicle types, prices, weight and dimension limits.
{
"status_code": 200,
"message": "",
"data": [
{
"status": "success",
"input": {
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"type": "pickup"
},
{
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia",
"type": "dropoff"
}
]
},
"quotations": [
{
"metadata": {
"quotationId": "3418817446335963964"
},
"courier": {
"service_id": "EP-CS0I",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Car",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "40kg",
"dimension": "50cmx50cmx50cm"
},
"pricing": {
"total_amount": 7.06,
"shipping_price": "7.06",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817446755394383"
},
"courier": {
"service_id": "EP-CS0F",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Bike",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "10kg",
"dimension": "30cmx30cmx30cm"
},
"pricing": {
"total_amount": 5.88,
"shipping_price": "5.88",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817660128027070"
},
"courier": {
"service_id": "EP-CS09",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "4X4",
"durations": "5mins",
"parcel_type_support": "Ideal for small fridge, washing machine, bike, 1-seater sofa",
"weight_limit": "250kg",
"dimension": "120cmx90cmx90cm"
},
"pricing": {
"total_amount": 27.06,
"shipping_price": "27.06",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817248574529909"
},
"courier": {
"service_id": "EP-CS05",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Large Van",
"durations": "5mins",
"parcel_type_support": "Ideal for washing machine, sofa, treadmill , large parcels",
"weight_limit": "800kg",
"dimension": "270cmx130cmx120cm"
},
"pricing": {
"total_amount": 57.65,
"shipping_price": "57.65",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817941557441277"
},
"courier": {
"service_id": "EP-CS0G",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Lorry 10-ft",
"durations": "5mins",
"parcel_type_support": "Ideal for queen size bed, fridge, 3-seater sofa, wardrobe",
"weight_limit": "1000kg",
"dimension": "290cmx150cmx150cm"
},
"pricing": {
"total_amount": 78.82,
"shipping_price": "78.82",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817672006300006"
},
"courier": {
"service_id": "EP-CS0M",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Lorry 14-ft",
"durations": "5mins",
"parcel_type_support": "Ideal for king size bed, large fridge, 3-seater sofa, wardro",
"weight_limit": "2500kg",
"dimension": "420cmx200cmx200cm"
},
"pricing": {
"total_amount": 125.29,
"shipping_price": "125.29",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3418817660128027086"
},
"courier": {
"service_id": "EP-CS0Y",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Van",
"durations": "5mins",
"parcel_type_support": "Ideal for small fridge, washing machine, bike, 1-seater sofa",
"weight_limit": "500kg",
"dimension": "170cmx100cmx120cm"
},
"pricing": {
"total_amount": 45.88,
"shipping_price": "45.88",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": null
},
"courier": {
"service_id": "EP-CS0R",
"courier_name": "PandaGo",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/pandaGo_pink.png"
},
"transport": {
"transportation_type": "Bike",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "15kg",
"dimension": "43cmx39cmx42cm"
},
"pricing": {
"total_amount": 7.06,
"shipping_price": "7.06",
"tax_amount": 0,
"currency": "MYR"
}
}
]
}
]
}
Main Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code |
| message | string | Status message |
| data | array | List of quotations with metadata |
Data Object Structure
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the request |
| input | object | Echo of submitted input |
| quotations | array | List of courier quotations |
Quotation Entry Structure
| Section | Parameter | Type | Description |
|---|---|---|---|
| metadata | quotationId | string | Unique quotation ID |
| courier | service_id | string | Service ID |
| courier_name | string | Courier name | |
| img_courier | string | Courier logo URL | |
| transport | transportation_type | string | Transport type (e.g., Bike, Car) |
| durations | string | Estimated delivery time | |
| parcel_type_support | string | Parcel suitability description | |
| weight_limit | string | Weight limit | |
| dimension | string | Max parcel dimension | |
| pricing | total_amount | string | Quotation price |
| currency | string | Currency (e.g., MYR) |
Sample Error Response
{
"status_code": 400,
"message": "Invalid input Error",
"data": [
"The waypoint 0 type field is required "
]
}
Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (requests)
const requestData = {
schedule_pickup_date: "2025-05-19",
schedule_pickup_time: "11:48:35",
timezone: "Asia/Kuala_Lumpur",
waypoint: [
{ type: "pickup", coordinates: { latitude: 5.34, longitude: 100.28 } },
{ type: "dropoff", coordinates: { latitude: 5.32, longitude: 100.28 } }
]
};
fetch('https://api.easyparcel.com/open_api/2025-09/ondemand/quotations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(requestData)
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$data = [
"schedule_pickup_date" => "2025-05-19",
"schedule_pickup_time" => "11:48:35",
"timezone" => "Asia/Kuala_Lumpur",
"waypoint" => [
["type" => "pickup", "coordinates" => ["latitude" => 5.34, "longitude" => 100.28]],
["type" => "dropoff", "coordinates" => ["latitude" => 5.32, "longitude" => 100.28]]
]
];
$ch = curl_init('https://api.easyparcel.com/open_api/2025-09/ondemand/quotations');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = 'https://api.easyparcel.com/open_api/2025-09/ondemand/quotations'
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
data = {
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{"type": "pickup", "coordinates": {"latitude": 5.34, "longitude": 100.28}},
{"type": "dropoff", "coordinates": {"latitude": 5.32, "longitude": 100.28}}
]
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for OnDemand Quotation
- Input Validation – Validate all fields before API call.
- Sorting Quotations – Sort by total amount for better user experience.
- Optional Features – Allow users to toggle extras like insurance or SMS alerts.
- Display Info – Always show courier logos, transport type, and delivery time.
OnDemand Order Submission
This guide explains how to submit an on-demand shipment order with and without applying a coupon, and the structure of the response received.
HTTP Request (OnDemand Submit Order)
POST https://api.easyparcel.com/ondemand/order
OnDemand Submit Order Request
Request Sample
{
"coupon_codes":["ad205174-d93d-4d6a-a5cc-1e989b0292eb"],
"origin_country": "MY",
"ondemand_service_id": "EP-CS0I",
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3418817446335963964"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "127849162",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Asa",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oreo",
"email": "oreo@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| coupon_codes | string | Optional | Apply coupon codes to get further discount |
| ondemand_service_id | string | Yes | ID of the selected on-demand service |
| origin_country | string | Yes | ISO 3166-1 alpha-2 country code |
| schedule_pickup_date | string | Optional | Date of pickup (YYYY-MM-DD) |
| schedule_pickup_time | string | Optional | Time of pickup (HH:MM:SS) |
| time_zone | string | Optional | Time zone of the pickup schedule |
| metadata | object | Yes | Additional metadata, e.g. quotationId |
| waypoint | array | Yes | Array of pickup and dropoff points |
| waypoint[*].point | numeric | Yes | Sequence index (e.g., 0 = pickup, 1 = dropoff) |
| waypoint[*].type | string | Yes | Type of stop; must be "pickup" or "dropoff" |
| waypoint[*].coordinates.latitude | numeric | Yes | Latitude of the location |
| waypoint[*].coordinates.longitude | numeric | Yes | Longitude of the location |
| waypoint[*].item | array | Yes | Items associated with the waypoint |
| waypoint[].item[].quantity | string | Yes | Quantity of the item |
| waypoint[].item[].description | string | Optional | Description of the item |
| waypoint[].item[].dimensions.height | string | Yes | Height of the item (in cm) |
| waypoint[].item[].dimensions.width | string | Yes | Width of the item (in cm) |
| waypoint[].item[].dimensions.length | string | Yes | Length of the item (in cm) |
| waypoint[].item[].dimensions.weight | string | Yes | Weight of the item (in kg) |
| waypoint[*].shipment_info.name | string | Yes | Name of the sender/receiver |
| waypoint[*].shipment_info.email | string | Optional | Email address |
| waypoint[*].shipment_info.phone_number_country_code | string | Yes | Phone number country code (e.g., MY) |
| waypoint[*].shipment_info.phone_number | string | Yes | Phone number |
| waypoint[*].shipment_info.address | string | Yes | Full address |
| waypoint[*].remark | string | Optional | Any additional notes or instructions |
OnDemand Submit Order Response
Sample Response
{
"status_code": 200,
"message": "Success",
"data": {
"booking_id": "EOD-150",
"ondemand_service_id": "EP-CS0I",
"order_number": "3418823367426527326",
"tracking_url": "https://share.lalamove.com/?MY100260129095828875410020097479892&lang=en_MY&sign=a990c1f88bbbc8424c76a58174b5bad8&source=api_wrapper",
"courier": {
"service_id": 3,
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"pricing_breakdown": {
"currency_code": "MYR",
"total_order_amount": "7.06",
"total_paid_amount": "7.06",
"shipment_amount": "7.06",
"tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"shipment": {
"origin_country": "MY",
"ondemand_service_id": "EP-CS0I",
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3418817446335963964"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "127849162",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Asa",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oreo",
"email": "oreo@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
}
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code (e.g., 200) |
| message | string | Success or error message |
| data | object | Contains booking details and shipment info |
Data Object
| Parameter | Type | Description |
|---|---|---|
| booking_id | string | Booking ID for the on-demand shipment |
| ondemand_service_id | string | ID of the selected on-demand service |
| order_number | string | Unique order number |
| tracking_url | string | URL to track the delivery |
| courier | object | Courier service information |
| pricing_breakdown | object | Price breakdown of the order |
| shipment | object | Submitted shipment details |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| service_id | int | Courier's service ID |
| courier_name | string | Name of the courier |
| img_courier | string | Logo URL of the courier |
Pricing Breakdown
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used (e.g., MYR) |
| total_order_amount | string | Final amount before any coupon |
| total_paid_amount | string | Amount paid after coupon applied |
| shipment_amount | string | Delivery cost without tax |
| tax_amount | string | Tax applied to the shipment |
| coupon_redeemed | string | Amount discounted using the coupon |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| coupon_codes | array | Applied coupon codes (if any) |
| origin_country | string | Country code of the shipment origin |
| ondemand_service_id | string | Service ID used |
| schedule_pickup_date | string | Scheduled pickup date |
| schedule_pickup_time | string | Scheduled pickup time |
| time_zone | string | Time zone of the schedule |
| metadata | object | Additional metadata (e.g., quotationId) |
| waypoint | array | Pickup and dropoff location details |
Waypoint Object
| Parameter | Type | Description |
|---|---|---|
| point | int | Sequence point (0=pickup, 1=dropoff) |
| type | string | Type of point ('pickup'/'dropoff') |
| remark | string | Remark or notes for the waypoint |
| coordinates | object | Latitude and longitude |
| item | array | Items associated with this stop |
| shipment_info | object | Sender or receiver contact details |
Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (Requests)
fetch("https://api.easyparcel.com/ondemand/order", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
},
body: JSON.stringify({ ... })
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$ch = curl_init("https://api.easyparcel.com/ondemand/order");
$data = [ ... ];
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = "https://api.easyparcel.com/ondemand/order"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
data = { ... }
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for Ondemand Submit Order
- Validate your data before sending the request, especially coordinates and item dimensions.
- Use quotationId from the Get Quotation API in
metadatato ensure pricing consistency. - Respect rate limits by not firing too many requests in a short time.
- Ensure date and time format follow
YYYY-MM-DDandHH:MM:SSstandards. - Always include proper contact details to avoid delivery failure.
- Secure your access token and never expose it in public repositories.
- Use sandbox/test environment for testing before going live.
OnDemand Coupon
The coupon feature allows customers to search for available promo codes and apply them during the shipment order submission. This helps users enjoy discounted rates or special benefits based on current promotional campaigns.
HTTP Request (OnDemand Coupon List)
Customers can retrieve a list of available coupon codes using the following endpoint:
GET https://api.easyparcel.com/open_api/2025-09/ondemand/get_coupon_list
This will return a list of valid promo codes available to use for the shipment from the user’s account, based on factors such as delivery type, courier, or region.
OnDemand Coupon Request
Submitting to the Coupon Listing Endpoint based on the submit shipment order endpoint request to get the available coupon for the shipment
Sample Coupon Listing Request:
{
"origin_country": "MY",
"ondemand_service_id": "EP-CS0I",
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3418817446335963964"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "127849162",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "asa",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oreo",
"email": "oreo@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
OnDemand Coupon Response
Sample Respone for the coupon listing
{
"status_code": 200,
"message": "4 coupon(s) available",
"data": {
"account_id": 438368,
"currency_code": "MYR",
"coupons": [
{
"coupon_code": "77f39c22-427a-44f1-8bff-e4f3752ba165",
"title": "Test Coupon 1",
"description": "Test ",
"discounted_amount": "5.01",
"discount_rate": "20.00%",
"valid_from_date": "2025-05-12 18:04:33",
"valid_to_date": "2025-09-14 18:04:33"
},
{
"coupon_code": "10101f8b-1dc5-49e0-b4d3-09c5deb76513",
"title": "Test Coupon",
"description": "Test",
"discounted_amount": "2.34",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "dfa5109a-2f35-427e-8482-9b0ab65c323f",
"title": "Test Coupon",
"description": "Test",
"discounted_amount": "2.10",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "ad205174-d93d-4d6a-a5cc-1e989b0292eb",
"title": "Test Coupon",
"description": "Test",
"discounted_amount": "1.89",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
}
]
}
}
Coupon Listing API - Response Parameters
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| message | string | Description of the response message |
| data | object | Container for coupon and account details |
data Object
| Parameter | Type | Description |
|---|---|---|
| account_id | int | The EasyParcel account ID |
| currency_code | string | Currency in which the discount is offered (e.g., MYR) |
| coupons | array | List of coupon objects available for use |
coupon Object (Inside coupons array)
| Parameter | Type | Description |
|---|---|---|
| coupon_code | string | Unique identifier for the coupon |
| title | string | Title or name of the coupon campaign |
| description | string | Description or note about the coupon |
| discounted_amount | string | Discount value in currency terms |
| discount_rate | string | Discount in percentage (e.g., "10.00%") |
| valid_from_date | string | Start datetime of coupon validity (UTC format) |
| valid_to_date | string | End datetime of coupon validity (UTC format) |
Applying Coupons
During the order submission process (e.g., /shipment/submit or /ondemand/shipment/submit), customers can apply a valid coupon code by including it in the request body.
To apply coupon just adding the coupon_codes parameters to the request
Sample Field in Submit Orders:
{
"coupon_codes":["ad205174-d93d-4d6a-a5cc-1e989b0292eb"],
"origin_country": "MY",
"ondemand_service_id": "EP-CS0I",
"schedule_pickup_date": "2025-05-19",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3418817446335963964"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "127849162",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Asa",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oreo",
"email": "oreo@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
If the coupon is valid and applicable, the discounted amount will be reflected in the final pricing.
Please ensure the coupon is valid and not expired before applying. For additional validation feedback, refer to the response message from the submission endpoint.
OnDemand Order Cancellation
This guide explains how to cancel an on-demand shipment order.
Endpoint URL
POST https://api.easyparcel.com/2025-09/ondemand/cancel
OnDemand Cancel Request
| Parameter | Type | Required | Description |
|---|---|---|---|
| booking_id | string | yes | booking number/id of the ondemand shipment |
-
Request Example
{
"booking_id": "EOD-150"
}
OnDemand Cancel Response
Sample Response
{
"status_code": 200,
"message": "success",
"data": [
{
"message": "Shipment cancelled successfully",
"booking_id": "EOD-150"
}
]
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code (e.g., 200) |
| message | string | Success or error message |
| data | object | Contains booking details and shipment info |
Cancellation
| Parameter | Type | Description |
|---|---|---|
| message | string | message for the cancelled status |
| booking_id | string | booking id/number of the ondemand status |
Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (Requests)
fetch("https://api.easyparcel.com/ondemand/cancel", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
},
body: JSON.stringify({
booking_id: "EOD-330"
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$ch = curl_init("https://api.easyparcel.com/ondemand/cancel");
$data = [
"booking_id" => "EOD-330"
];
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = "https://api.easyparcel.com/ondemand/cancel"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
data = {
"booking_id": "EOD-330"
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for Ondemand Cancel Order
- Always include a valid
booking_idwhen attempting to cancel an order. - Ensure the order is eligible for cancellation (i.e., not already picked up or completed).
- Handle the response gracefully, including possible failure messages.
- Use test credentials in sandbox mode for testing integration before going live.
- Rate limit your API calls to avoid service throttling or rejection.
- Log your cancellation attempts for traceability and support reference.
- Secure your access token and never expose it in public repositories or front-end code.
Account Related Endpoints
Account related will provides features related to your easyparcel account such as receiving account details.
Wallet Balance
This endpoint allows users to retrieve their current wallet balance and free credit information.
HTTP Request (Wallet)
GET https://api.easyparcel.com/open_api/2025-09/wallet
Request Wallet Parameters
This endpoint does not require any request parameters. Authentication is handled through Oauth 2.0 access token.
Request Sample for Wallet
No request body required
Response Wallet Parameters
Response Sample for Wallet
{
"status_code": 200,
"message": "Success",
"data": {
"wallet": [
{
"balance": 9999999123.88,
"currency": "MYR"
}
],
"free_credit_wallet": [
{
"balance": 0,
"currency": "MYR"
}
]
}
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | object | Contains wallet information |
Data Object
| Parameter | Type | Description |
|---|---|---|
| wallet | array | Array of wallet balances |
| free_credit_wallet | array | Array of free credit balances |
Wallet Object
| Parameter | Type | Description |
|---|---|---|
| balance | double | Available balance in the wallet |
| currency | string | Currency code of the balance |
Free Credit Wallet Object
| Parameter | Type | Description |
|---|---|---|
| balance | double | Available free credits |
| currency | string | Currency code of the free credits |
Error Response for Wallet
If there's an authentication issue or server error, the API will return an error response:
{
"status_code": 401,
"message": "Unauthorized access",
"data": null
}
Usage Notes for Wallet
- This endpoint provides the current balance in your EasyParcel wallet, which can be used for shipping services.
- The response includes both regular wallet balance and free credit balance.
- The balance is updated in real-time and reflects the current available amount for shipping services.
- Wallet balances can be topped up through the EasyParcel dashboard.
- Always ensure your account has sufficient balance before submitting shipment orders to avoid processing delays.
Webhooks
How to Subscribe to Webhooks
Prerequisites
Before setting up webhooks, ensure you have: - An active EasyParcel developer account - A configured app in the Developer Hub - A valid endpoint URL that can receive POST requests - Your endpoint configured to handle webhook payloads
Subscription Steps
Follow these steps to subscribe to webhooks:
1. 🎯 Navigate to App Settings
- Go to Developer Hub Dashboard
- Click on Apps
- Select Settings on the app you wish to configure webhooks for
2. 📡 Access Webhook Configuration
- In the left sidebar, click Webhook
- Click the Add Endpoint button
3. ⚙️ Configure Webhook Details
- Enter Endpoint URL: Input the URL that will receive the webhook payload
- Select Webhook Topic: Choose the event(s) you want to subscribe to from the available options
- Verify Configuration: Double-check your URL and selected topics
4. 💾 Save Configuration
- Press Save to confirm your webhook settings
- Your webhook endpoint will be validated
5. ✅ Confirmation
- Done! Your webhook is now active and will be triggered according to your selected topics
- Test your endpoint to ensure it's receiving webhook data correctly
Webhook Topics
| Topic ID | Webhook Topic Name | Description |
|---|---|---|
| 1 | Ondemand Order Status Update | Triggered when an on-demand order status changes |
| 2 | Shipment Status Update | Triggered when a shipment status changes |
| 3 | Shipment AWB Update | Triggered when a shipment AWB (Air Waybill) is updated |
| 4 | Tracking Status Update | Triggered when package tracking status is updated |
| 5 | Shipment Created | Triggered when a new shipment is created |
Webhook Sample Payload:
//Shipment Status Update Sample:
{
"topic": "shipment.awb.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "238725129086",
"awb_url":"http:\/\/demo.connect.easyparcel.my\/?ac=AWBLabel&id=QmIxTE43eHQjMTYzMDQwMTI%3D",
"tracking_url":"https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001523"
}
//Shipment AWB Update Sample:
{
"topic": "shipment.awb.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "23872512999",
"awb_url":"http:\/\/demo.connect.easyparcel.my\/?ac=AWBLabel&id=QmIxTE43eHQjMTYzMDQwAAA%3D",
"tracking_url":"https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001999"
}
//Shipment AWB Update Sample:
{
"topic": "shipment.tracking.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "238725129086",
"latest_shipment_status_code":5,
"latest_tracking_status": "Deliverd To Suntech",
"timestamp":"2017-10-28 11:40:00",
"status_log":[
"0":{
"timestamp":"2017-10-28 11:40:00",
"shipment_status_code":5,
"tracking_status" : "Deliverd To Suntech"
},
"1":{
"timestamp":"2017-06-28 12:00:00",
"shipment_status_code":3,
"tracking_status":"Parcel has been collected at Penang"
}
]
}
//Shipment Create Sample:
{
"shipment_number": "WEBHOOK-TEST-001",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"sender_name": "Test Sender",
"receiver_name": "Test Receiver",
"sender_phone_number": "0123456789",
"receiver_phone_number": "0987654321",
"sender_email": "sender@test.com",
"receiver_email": "receiver@test.com",
"sender_address1": "Test Address 1",
"receiver_address1": "Test Address 1",
"sender_postcode": "12345",
"receiver_postcode": "54321",
"sender_city": "Test City",
"receiver_city": "Test City",
"sender_country_code": "MY",
"receiver_country_code": "MY",
"weight": 1.0,
"length": 10,
"width": 10,
"height": 10,
"service_id": 1,
"courier_id": 1,
"status": 1
}
//Ondemand Order Status Update Sample:
{
"topic": "ondemand.status.update",
"order_number": "EODWEBHOOK-TEST-001",
"tracking_url": "https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001523",
"status": 0,
"timeline": ,
"driver": {
"id": "81994", "name": "TestDriver 09090", "phone": "+6090909090", "photo": "", "rating": "", "vehicle": {"model": "", "licensePlate": "VP5734736", "physicalVehicleType": "Bike"}, "coordinates": {"latitude": 0, "longitudelatitude": 0 }
},
"event_date": "2025-06-06 04:21:07",
"waypoint": [
{"pod": null, "coordinate": {"latitude": 5.325513957, "longitude": 100.2862732}},
{"pod": "http://sg-oimg-pre.lalamove.com/appdriver/pre/appdriver/2021/07/05/1625479646347738192598.png", "coordinate": {"latitude": 5.325513957, "longitude": 100.2862732}}
],
}
Usage Notes for Webhooks
- Multiple Subscriptions: You can subscribe to multiple topics for the same endpoint
- Event Filtering: Choose only the topics relevant to your application to reduce unnecessary webhook calls
Important Notes for Webhooks
- Endpoint Requirements: Your URL must be publicly accessible and able to handle POST requests
- Multiple Topics: You can subscribe to multiple webhook topics for the same endpoint
- Payload Format: All webhooks send JSON payloads with event-specific data
- Response Expected: Your endpoint should return a 200 status code to acknowledge receipt
- Retry Logic: Failed webhook deliveries may be retried automatically
Testing Your Webhook
After setup, verify your webhook is working: 1. Trigger a test event in your app 2. Check your endpoint logs for incoming requests 3. Verify the payload structure matches your expectations 4. Ensure your endpoint responds with HTTP 200
🛠️ Troubleshooting for webhooks
Common Issues: - Endpoint not receiving data: Verify URL is publicly accessible - SSL/HTTPS required: Ensure your endpoint uses HTTPS - Timeout errors: Your endpoint should respond quickly (within 30 seconds) - Invalid responses: Return proper HTTP status codes
References
ISO 3166
At EasyParcel, we adhere to the ISO 3166 standard for the identification of states, provinces, and zones. For example, the code "MY-07" corresponds to the state of Penang in Malaysia.
ISO 3166 is a standard published by the International Organization for Standardization (ISO) that defines codes for the names of countries, dependent territories, special areas of geographical interest, and their principal subdivisions (e.g., provinces or states). The official name of the standard is Codes for the representation of names of countries and their subdivisions. make this sentences better
Conutry Code
| Short Country Name | Full Country Name |
|---|---|
| SR | SURINAME |
| SD | SUDAN |
| VC | ST. VINCENT |
| XM | ST. MAARTEN |
| LC | ST. LUCIA |
| KN | ST. KITTS |
| XE | ST. EUSTATIUS |
| BL | ST. BARTHELEMY |
| LK | SRI LANKA |
| ES | SPAIN |
| ZA | SOUTH AFRICA |
| XS | SOMALILAND (NORTH SOMALIA) |
| SO | SOMALIA |
| SB | SOLOMON ISLANDS |
| SI | SLOVENIA |
| SK | SLOVAKIA |
| SG | SINGAPORE |
| SL | SIERRA LEONE |
| SC | SEYCHELLES |
| RS | SERBIA |
| SN | SENEGAL |
| SA | SAUDI ARABIA |
| ST | SAO TOME AND PRINCIPE |
| SM | SAN MARINO |
| WS | SAMOA |
| MP | SAIPAN |
| RW | RWANDA |
| RU | RUSSIAN FEDERATION |
| RO | ROMANIA |
| RE | REUNION |
| QA | QATAR |
| PR | PUERTO RICO |
| PT | PORTUGAL |
| PL | POLAND |
| PH | PHILIPPINES |
| PE | PERU |
| PY | PARAGUAY |
| PG | PAPUA NEW GUINEA |
| PA | PANAMA |
| PW | PALAU |
| PK | PAKISTAN |
| OM | OMAN |
| NO | NORWAY |
| NU | NIUE |
| NG | NIGERIA |
| NE | NIGER |
| NI | NICARAGUA |
| NZ | NEW ZEALAND |
| NC | NEW CALEDONIA |
| XN | NEVIS |
| NL | NETHERLANDS |
| NP | NEPAL |
| NR | NAURU |
| NA | NAMIBIA |
| MM | MYANMAR |
| MA | MOROCCO |
| MS | MONTSERRAT |
| ME | MONTENEGRO |
| MN | MONGOLIA |
| MC | MONACO |
| MD | MOLDOVA, REPUBLIC OF |
| FM | MICRONESIA, FEDERATED STATES OF |
| MX | MEXICO |
| YT | MAYOTTE |
| MU | MAURITIUS |
| MR | MAURITANIA |
| MQ | MARTINIQUE |
| MH | MARSHALL ISLANDS |
| MT | MALTA |
| ML | MALI |
| MV | MALDIVES |
| MW | MALAWI |
| MY | MALAYSIA |
| MG | MADAGASCAR |
| MK | MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF |
| MO | MACAU |
| LU | LUXEMBOURG |
| LT | LITHUANIA |
| LI | LIECHTENSTEIN |
| LY | LIBYA |
| LR | LIBERIA |
| LS | LESOTHO |
| LB | LEBANON |
| LV | LATVIA |
| LA | LAO PEOPLE'S DEMOCRATIC REPUBLIC |
| KG | KYRGYZSTAN |
| KW | KUWAIT |
| XK | KOSOVO |
| KR | KOREA, REPUBLIC OF |
| KP | KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF |
| KI | KIRIBATI |
| KE | KENYA |
| KZ | KAZAKHSTAN |
| JO | JORDAN |
| JE | JERSEY |
| JP | JAPAN |
| JM | JAMAICA |
| IT | ITALY |
| IL | ISRAEL |
| IE | IRELAND |
| IQ | IRAQ |
| IR | IRAN, ISLAMIC REPUBLIC OF |
| ID | INDONESIA |
| IN | INDIA |
| IS | ICELAND |
| HU | HUNGARY |
| HK | HONG KONG |
| HN | HONDURAS |
| HT | HAITI |
| GY | GUYANA |
| GW | GUINEA BISSAU |
| GN | GUINEA REPUBLIC |
| GG | GUERNSEY |
| GT | GUATEMALA |
| GU | GUAM |
| GP | GUADELOUPE |
| GD | GRENADA |
| GL | GREENLAND |
| GR | GREECE |
| GI | GIBRALTAR |
| GH | GHANA |
| DE | GERMANY |
| GE | GEORGIA |
| GM | GAMBIA |
| GA | GABON |
| ZW | ZIMBABWE |
| FR | FRANCE |
| FI | FINLAND |
| ZM | ZAMBIA |
| FJ | FIJI |
| YE | YEMEN |
| FO | FAROE ISLANDS |
| FK | FALKLAND ISLANDS (MALVINAS) |
| ET | ETHIOPIA |
| VI | VIRGIN ISLANDS, U.S. |
| EE | ESTONIA |
| VG | VIRGIN ISLANDS, BRITISH |
| ER | ERITREA |
| GQ | EQUATORIAL GUINEA |
| SV | EL SALVADOR |
| EG | EGYPT |
| VN | VIETNAM |
| EC | ECUADOR |
| TP | EAST TIMOR |
| VE | VENEZUELA |
| DO | DOMINICAN REPUBLIC |
| DM | DOMINICA |
| DJ | DJIBOUTI |
| VU | VANUATU |
| DK | DENMARK |
| CZ | CZECH REPUBLIC |
| CY | CYPRUS |
| CU | CUBA |
| UZ | UZBEKISTAN |
| UY | URUGUAY |
| HR | CROATIA |
| CI | COTE D'IVOIRE |
| CR | COSTA RICA |
| CK | COOK ISLANDS |
| CD | CONGO, THE DEMOCRATIC REPUBLIC OF THE |
| UM | UNITED STATES MINOR OUTLYING ISLANDS |
| CG | CONGO |
| KM | COMOROS |
| CN | CHINA |
| US | UNITED STATES |
| GF | FRENCH GUIANA |
| AN | NETHERLANDS ANTILLES |
| MZ | MOZAMBIQUE |
| CW | CURACAO |
| CO | COLOMBIA |
| CL | CHILE |
| TD | CHAD |
| CF | CENTRAL AFRICAN REPUBLIC |
| KY | CAYMAN ISLANDS |
| GB | UNITED KINGDOM |
| CV | CAPE VERDE |
| AE | UNITED ARAB EMIRATES |
| IC | CANARY ISLANDS, THE |
| CA | CANADA |
| UA | UKRAINE |
| CM | CAMEROON |
| KH | CAMBODIA |
| UG | UGANDA |
| BI | BURUNDI |
| BF | BURKINA FASO |
| BG | BULGARIA |
| BN | BRUNEI DARUSSALAM |
| TV | TUVALU |
| BR | BRAZIL |
| TC | TURKS AND CAICOS ISLANDS |
Add-On Feature: EasyParcel Tracking Notification
Real-time parcel tracking has become essential in today’s fast-paced logistics environment. To improve user experience and enhance transparency, EasyParcel offers multiple tracking notification methods as add-on features for standard delivery services.
📲 Tracking SMS
Tracking SMS allows recipients to receive real-time parcel status updates via SMS. Notifications are automatically sent when the parcel is dispatched, in transit, or out for delivery. This is especially helpful for users who are always on the go and prefer quick updates without logging into the platform.
📧 Tracking Email
With Tracking Email, recipients receive status updates directly in their inboxes. This is an ideal solution for users who rely heavily on email and want to maintain a full history of parcel status in one place. Updates are triggered automatically as the parcel progresses through various delivery stages.
💬 Tracking WhatsApp
WhatsApp Tracking is a modern, interactive way to stay informed about parcel movements. Notifications are delivered straight to the recipient’s WhatsApp chat, making it easy to follow updates in real-time and share parcel progress with others if needed.
These tracking features are available for EasyParcel users across various supported countries. Please refer to your local EasyParcel platform for feature availability and pricing. You may also run the Get Shipment Quotation endpoint to retrieve pricing details for available tracking features. These tracking features can be activated through the Submit Order endpoint during order creation.
EasyParcel Coupon Feature
EasyParcel’s coupon feature offers customers a convenient way to enjoy special discounts, seasonal promotions, and loyalty rewards. These promo codes help users save on shipping costs and encourage engagement through exclusive campaign offers.
🎁 What Are EasyParcel Coupons?
Coupons are promo codes issued by EasyParcel that provide instant rebates or special perks when applied to a shipment. They can be targeted based on delivery types, couriers, regions, or customer eligibility (e.g., new users, festive deals).
🔍 Where to Find Coupons
Customers can browse available coupons directly through the EasyParcel platform. These offers may appear on promotional banners, in user dashboards, or be provided via campaigns. Developers can also retrieve available coupons programmatically using the designated API endpoint.
🧾 How to Use Coupons
To enjoy a discount, users simply need to enter the valid coupon code during order submission. If the coupon meets the required conditions, the discount will be reflected in the final price.
Please note that coupon availability and eligibility may vary by country, courier, and shipping method. Always check the terms associated with each coupon before use.
Cancel Order
This section introduces the cancellation features available for both standard and ondemand shipments on the EasyParcel platform.
❗ Important Cancellation Conditions
- 7-Day Limit: Cancellation requests must be submitted within 7 days from the scheduled collection date.
- No Cancellation After Pickup: Once the courier driver has picked up the parcel, cancellation is no longer permitted.
- Refunds: If the cancellation is successful, the shipment cost will be refunded to the user's credit wallet.
📡 Relevant Endpoints
Bulk Cancellation Support:
- Standard shipments support bulk cancellation.
- Ondemand shipments must be cancelled individually.
/shipment/cancel– for standard shipment cancellations./ondemand/shipment/cancel– for ondemand shipment cancellations.
EasyParcel API Standards
This document outlines the standard formats for requests and responses when working with the EasyParcel API.
Request Format Standards
General Guidelines
- All requests must be sent as HTTP POST requests
- Content-Type header should be set to
application/json - Authentication is handled via Oauth 2.0 access token in the headers
- All request payloads should be valid JSON objects
- DateTime values should use the format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS
Common Request Structure
Most EasyParcel API endpoints follow a consistent request format:
Single Resource Requests - Simple requests with a single parameter set:
json { "parameter1": "value1", "parameter2": "value2" }Batch Requests - Requests involving multiple items follow an array pattern:
json { "resource_name": [ { /* item 1 details */ }, { /* item 2 details */ } ] }
Example Request Types
Shipment Submission
Batch format with shipment array containing multiple shipment objects:
{
"shipment": [
{
"service_id": "EP-CS09Q",
"collection_date": "2025-05-02",
"weight": 2.5,
"height": 30,
"length": 40,
"width": 20,
"item": [ /* items array */ ],
"sender": { /* sender details */ },
"receiver": { /* receiver details */ },
"feature": { /* feature settings */ }
},
// Additional shipments...
]
}
Quotation Request
Similar batch format with shipment array containing multiple quote requests:
{
"shipment": [
{
"sender": {
"postcode": "10150",
"subdivision_code": "MY-02",
"country": "MY"
},
"receiver": {
"postcode": "018916",
"subdivision_code": "SG-04",
"country": "SG"
},
"parcel_value": 50,
"weight": 0.5,
"width": 5,
"length": 5,
"height": 5
},
// Additional quote requests...
]
}
Shipment Listing Request
Simple parameter format for filtering and pagination:
{
"limit": 3,
"before_shipment_number": "ES-2504-B944M",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Response Format Standards
General Guidelines
- All responses are returned as JSON objects
- Every response includes
status_code,message, anddatafields - Successful operations return status code 200
- Error details are provided in both the message and data sections
- Batch operations provide individual success/failure information for each item
Common Response Structure
Success Response Patterns
/* Single Resource Response */
{
"status_code": 200,
"message": "success",
"data": [
/* Response data objects */
]
}
/* Batch Operation Response */
{
"status_code": 200,
"message": "2 requests success, 1 request error.",
"data": [
{
"status": "success",
"message": "Order Processed",
"item_id": "12345"
},
{
"status": "success",
"message": "Order Processed",
"item_id": "12346"
},
{
"status": "error",
"message": "Invalid postal code",
"item_id": "12347"
}
]
}
Error Response Patterns
/* Request Validation Error */
{
"status_code": 400,
"message": "Validation failed",
"data": {
"errors": [
"The service_id field is required",
"The collection_date field is required"
]
}
}
/* Resource Not Found */
{
"status_code": 404,
"message": "No Order with shipment_number ES-2504-3WYYP found from this account",
"data": []
}
/* Authentication Error */
{
"status_code": 401,
"message": "Invalid Oauth 2.0 access token",
"data": null
}
/* Partial Success in Batch Operations */
{
"status_code": 200,
"message": "1 requests success, 2 request error.",
"data": [
{
"status": "success",
"message": "Order Cancelled",
"shipment_number": "ES-2504-WZ9VY"
},
{
"status": "error",
"message": "Shipment Already Cancelled",
"shipment_number": "ES-2504-JUB4T"
},
{
"status": "error",
"message": "Shipment Not Found",
"shipment_number": "ES-2504-INVALID"
}
]
}
Common Field Types
| Field Type | Format | Example |
|---|---|---|
| Date | YYYY-MM-DD | 2025-05-02 |
| DateTime | YYYY-MM-DD HH:MM:SS | 2025-05-02 14:30:00 |
| Weight | Numeric (kg) | 2.5 |
| Dimensions | Numeric (cm) | 30 |
| Currency | ISO Currency Code | MYR |
| Country Code | ISO Country Code | MY |
| Subdivision Code | ISO 3166-2 code | MY-07 |
| Phone Code | With "+" prefix | +60 |
| Boolean | true/false | true |
Best Practices
- Validate Input: Always validate request parameters against the API documentation before submission
- Check Status Codes: Always check the status_code in the response
- Handle Batch Responses: For batch operations, check individual status values for each item
- Error Handling: Implement proper error handling based on the error message patterns
- Pagination: For list endpoints, use the provided pagination mechanisms with
limitandbefore_shipment_number - Date Ranges: When using date ranges, ensure
date_fromis earlier thandate_to - Field Lengths: Respect the maximum field lengths specified in the API documentation
Notes on API Versioning
The API version is included in the URL path: /2025-09/
Always use the appropriate version for your implementation to ensure compatibility.
EasyParcel API Error Handling Guide
This document outlines the common error patterns and recommended handling strategies when working with the EasyParcel API.
Error Response Patterns
The EasyParcel API returns specific error formats depending on the type of error encountered. Understanding these patterns will help you implement proper error handling in your integration.
Authentication Errors
When authentication fails, you'll receive a response in this format:
{
"error": {
"statusCode": 401,
"status": 401,
"code": 401,
"name": "invalid_token"
},
"status_code": 401
}
Common Authentication Error Codes
| Error Name | Description | Recommended Action |
|---|---|---|
| invalid_token | The Oauth 2.0 access token is invalid or expired | Verify your Oauth 2.0 access token and request a new one if needed |
| missing_token | No Oauth 2.0 access token was provided in the request | Ensure Oauth 2.0 access token is included in the request header |
| insufficient_scope | The Oauth 2.0 access token doesn't have permission for this action | Request appropriate permissions for your Oauth 2.0 access token |
Validation Errors
Single Resource Validation
For single resource operations with validation errors:
{
"status_code": 400,
"message": "Validation error",
"data": {
"errors": [
"The service id field is required",
"The collection date field is required"
]
}
}
Batch Operation Errors
For batch operations, the API may return a mix of successful and failed operations:
Complete Batch Failure
{
"status_code": 200,
"message": "0 requests success, 3 request error.",
"data": [
{
"order_details": {
"account_id": "438671"
},
"pricing": {
"currency_code": "MYR",
"total_amount": "0.00",
"total_tax_amount": "0.00"
},
"shipments": [
{
"status": "error",
/* shipment details */
"errors": [
"The service id field is required",
"The collection date field is required",
"The receiver phone number country code field is required",
"The receiver phone number field is required",
"The receiver address 1 field is required"
]
},
/* additional failed shipments */
]
}
]
}
Partial Success in Batch Operations
{
"status_code": 200,
"message": "1 request success, 1 request error.",
"data": [
{
"order_details": {
"order_number": "EI-2504-6WFXC",
"account_id": 438671
},
"pricing": {
"currency_code": "MYR",
"total_amount": "27.83",
"total_tax_amount": "1.63"
},
"shipments": [
{
"status": "success",
/* successful shipment details */
},
{
"status": "error",
/* failed shipment details */
"errors": [
"The service id field is required",
"The collection date field is required"
]
}
]
}
]
}
Quotation Errors
Quotation endpoints also follow the batch processing pattern, where some items may succeed while others fail:
{
"status_code": 200,
"message": "1 request success, 2 request error.",
"data": [
{
"status": "success",
"input": { /* input details */ },
"quotations": [ /* quotation results */ ]
},
{
"status": "error",
"input": { /* input details */ },
"errors": [
"The receiver postcode is invalid"
]
},
{
"status": "error",
"input": { /* input details */ },
"errors": [
"The receiver country field is required"
]
}
]
}
Common Error Messages
Here are some common error messages you may encounter and how to resolve them:
Request Validation Errors
| Error Message | Possible Cause | Resolution |
|---|---|---|
| "The service id field is required" | Missing service_id in request | Include a valid service_id from courier list |
| "The collection date field is required" | Missing or invalid collection_date | Provide a valid date in YYYY-MM-DD format |
| "The receiver phone number field is required" | Missing receiver phone number | Include the receiver's phone number |
| "The receiver address 1 field is required" | Missing primary address line | Include the first line of the receiver's address |
| "The receiver postcode is invalid" | Invalid or non-existent postal code | Verify the postal code with the courier service |
| "The receiver country field is required" | Missing country code | Include a valid country code (e.g., "MY" for Malaysia) |
Business Logic Errors
| Error Message | Possible Cause | Resolution |
|---|---|---|
| "Shipment Already Cancelled" | Attempting to cancel an already cancelled shipment | Check shipment status before cancellation request |
| "No Order with shipment_number X found" | Incorrect shipment number or not owned by account | Verify the shipment number belongs to your account |
| "Shipment Cannot Be Cancelled" | Shipment is in a state that can't be cancelled | Only shipments in certain states can be cancelled |
| "Weight exceeds service limits" | Parcel exceeds courier weight restrictions | Choose a different service or reduce parcel weight |
| "Service not available for origin/destination" | Route not serviced by selected courier | Choose a different courier service |
Error Handling Best Practices
1. Check Status Code and Message
Always check both the status_code and message fields to properly identify errors. A 200 status code does not always mean complete success in batch operations.
2. Handle Batch Operations Carefully
For batch operations:
- Parse the message field to determine success/error counts
- Iterate through each item in the data array
- Check the status field of each item
- Process successful items and handle errors for failed items
3. Implement Retry Logic
For transient errors (e.g., network issues, temporary service unavailability), implement a retry mechanism with exponential backoff.
4. Log Detailed Error Information
Log detailed error information for troubleshooting, including: - Request parameters - Complete error response - Timestamp - API endpoint
5. Handle Validation Errors Proactively
Implement client-side validation based on known API requirements to reduce validation errors.
6. Check for Partial Success
Always assume batch operations may partially succeed and handle accordingly:
// Example handling of a batch response
function handleBatchResponse(response) {
console.log(`Processing response: ${response.message}`);
if (response.status_code !== 200) {
return handleNonSuccessStatusCode(response);
}
// Extract success/failure counts from message
const messageParts = response.message.split(',');
const successCount = parseInt(messageParts[0].match(/\d+/)[0]);
const errorCount = parseInt(messageParts[1].match(/\d+/)[0]);
console.log(`Shipments: ${successCount} successful, ${errorCount} failed`);
// Process data
response.data.forEach(order => {
if (order.shipments) {
order.shipments.forEach(shipment => {
if (shipment.status === 'success') {
processSuccessfulShipment(shipment);
} else {
handleFailedShipment(shipment);
}
});
}
});
}
Authentication Error Recovery
If you encounter authentication errors:
- Verify your Oauth 2.0 access token is correct
- Check if your Oauth 2.0 access token has expired
- Request a new Oauth 2.0 access token if necessary
- Ensure your system securely stores the Oauth 2.0 access token
- Implement automatic token refresh if supported
Common HTTP Status Codes
| Status Code | Description | Handling Strategy |
|---|---|---|
| 200 | Success (may include errors) | Check message and individual item status |
| 400 | Bad Request | Fix request parameters based on error details |
| 401 | Unauthorized | Refresh or update API credentials |
| 403 | Forbidden | Request appropriate permissions |
| 404 | Not Found | Verify resource identifiers |
| 429 | Too Many Requests | Implement rate limiting and backoff strategy |
| 500 | Server Error | Retry with exponential backoff |
Troubleshooting Guide
Oauth 2.0 access token Issues
- Ensure Oauth 2.0 access token is not expired
- Verify Oauth 2.0 access token is correctly included in the authorization header
- Check if your account has the necessary permissions
Invalid Input
- Validate all required fields are present
- Ensure postal codes are valid for the respective countries
- Verify dimensions and weights are within courier limitations
Service Availability
- Check if selected service is available for the specific route
- Verify the courier is operational on the requested collection date
- Confirm service availability for international routes
Shipment Status Issues
- Verify shipment status before attempting to modify or cancel
- Check if the shipment number exists and belongs to your account
- Ensure operations are performed within allowed timeframes (e.g., cancellation window)
Contact Support
If you encounter persistent errors that cannot be resolved through this guide, contact EasyParcel support with the following information:
- Complete request and response details
- Timestamp of the request
- API endpoint used
- Description of the expected vs. actual behavior
- Steps taken to troubleshoot the issue
Pagination Guide for EasyParcel API
This document outlines the pagination mechanism used in the EasyParcel API for endpoints that return multiple records, such as shipment listings and on-demand service listings.
Pagination Overview
EasyParcel API uses cursor-based pagination for list endpoints. This method is more efficient than traditional page number-based pagination, especially for large datasets.
How Pagination Works
- You specify a limit of records to return in each request
- The API returns records sorted by the latest first
- To retrieve the next set of records, you use the last record's identifier as a cursor
Pagination Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Number of records to return (default: 10, max: 250) |
| before_shipment_number | string | No | ID of the record to paginate from |
Additionally, you can use filtering parameters along with pagination:
| Parameter | Type | Required | Description |
|---|---|---|---|
| shipment_status_code | string | No | Filter by shipment status |
| date_from | date | No | Start date for filtering (YYYY-MM-DD) |
| date_to | date | No | End date for filtering (YYYY-MM-DD) |
Pagination Example
Initial Request
The first request does not include a before_shipment_number parameter:
{
"limit": 3,
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Subsequent Requests
For the next batch of records, include the before_shipment_number from the last record in the previous response:
{
"limit": 3,
"before_shipment_number": "ES-2504-B944M",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Implementation Guide
Client-Side Pagination Logic
Here's a pseudocode example of how to implement pagination in your client application:
// Initial request - no cursor
let params = {
limit: 20,
shipment_status_code: "7",
date_from: "2025-04-01",
date_to: "2025-04-23"
};
async function fetchAllShipments() {
let allShipments = [];
let hasMoreRecords = true;
while (hasMoreRecords) {
const response = await apiRequest('/shipment/list', params);
// Add fetched shipments to our collection
allShipments = [...allShipments, ...response.data];
// If we received fewer records than requested, we've reached the end
if (response.data.length < params.limit) {
hasMoreRecords = false;
} else {
// Set cursor for next request using the last record's ID
const lastShipment = response.data[response.data.length - 1];
params.before_shipment_number = lastShipment.shipment_number;
}
}
return allShipments;
}
Loading Records On Demand
For user interfaces, you may want to implement "load more" functionality:
let currentParams = {
limit: 20,
shipment_status_code: "7"
};
let shipments = [];
async function loadMoreShipments() {
const response = await apiRequest('/shipment/list', currentParams);
// Add new shipments to the existing list
shipments = [...shipments, ...response.data];
// Update button state
const loadMoreButton = document.getElementById('load-more');
if (response.data.length < currentParams.limit) {
loadMoreButton.style.display = 'none'; // Hide when no more records
} else {
// Update cursor for next request
const lastShipment = response.data[response.data.length - 1];
currentParams.before_shipment_number = lastShipment.shipment_number;
}
// Update UI with new shipments
renderShipments(shipments);
}
Pagination for On-Demand Listings
The on-demand listing endpoint (/open_api/2025-09/ondemand/list) follows the same pagination pattern as shipment listings, but uses before_booking_number instead of before_shipment_number:
{
"limit": 3,
"before_booking_number": "EOD-123",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Best Practices
- Default Limit: If not specified, the API uses a default limit of 10 records per request
- Maximum Limit: The maximum limit is 250 records per request
- Sort Order: Results are always sorted with the most recent records first
- Filter Efficiency: Use status and date filters to reduce the dataset before pagination
- Cursor Storage: Always store the last cursor for error recovery
- Empty Results: If a request returns empty results, you've reached the end of the dataset
Common Issues and Solutions
| Issue | Solution |
|---|---|
| Missing records in pagination sequence | Ensure you're using the correct cursor value |
| Too many API calls for large datasets | Increase the limit parameter (up to 250) |
| Need to restart pagination from beginning | Remove the before_shipment_number parameter |
| Results not matching expected criteria | Review filter parameters for correct formatting |
Notes on Resource Usage
- Using appropriate limit values and filters helps reduce API calls
- Retrieving all records in smaller batches is more reliable than requesting large batches
- Consider implementing caching for frequently accessed records
Switching to Live
If you've completed testing in the DEMO/Sandbox environment and would like to switch to the live environment, please follow the steps below:
- Run the "Get New Access Token" flow.
- Once you reach the "Select Account" section, choose and switch to your live account.
That's it! You have successfully switched to the live environment.
Version (2025-06)
Here we will provide you with the latest version of the EasyParcel API, along with any important changes or updates.
Standard Shipping
Standard shipping provides scheduled delivery with cost-effective solutions for businesses with regular shipping needs. This service offers comprehensive tracking, multiple courier options, and flexible additional features.
Shipping Workflow
Standard Shipping Flow
├── Order Flow
│ ├── Get Quotation
│ ├── Get Coupon Listing
│ └── Submit Order
└── Management Flow
├── Get Shipment Listing
├── Get Shipment Details
└── Cancel Orders
Shipment Quotations
Get shipment quotations from all available courier companies on the EasyParcel platform. Provide sender and receiver addresses to receive pricing details, available services, and additional features.
Authentication (Standard Quotation)
To authorize, use this code:
curl "https://api.easyparcel.com/open_api/2025-06/shipment/quotations" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
const headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
};
$headers = [
'Authorization: Bearer YOUR_ACCESS_TOKEN',
'Content-Type: application/json'
];
headers = {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
}
EasyParcel uses Oauth 2.0 to allow access to the API. You can register a new Oauth 2.0 access at our developer portal.
The API expects the Oauth 2.0 to be included in all API requests to the server in a header that looks like the following:
Authorization: Bearer YOUR_ACCESS_TOKEN
HTTP Request (Quotation)
POST https://api.easyparcel.com/open_api/2025-06/shipment/quotations
Quotation Request
Example Request:
{
"shipment": [
{
"sender": {
"postcode": "11900",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "14000",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value":20,
"weight": 2.5,
"width": 5,
"length": 6,
"height": 7
},
{
"sender": {
"postcode": "10150",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "14000",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value":50,
"weight": 0.5,
"width": 5,
"length": 5,
"height": 5
},
{
"sender": {
"postcode": "10150",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "09000",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value":50,
"weight": 0.5,
"width": 5,
"length": 5,
"height": 5
}
]
}
Sender Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string(10) | true | Sender's postcode |
| subdivision_code | string(35) | true | Sender's subdivision code (ISO 3166) |
| country | string(2) | true | Sender's country code |
Receiver Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string(10) | true | Receiver's postcode |
| subdivision_code | string(35) | true | Receiver's subdivision code (ISO 3166) |
| country | string(2) | true | Receiver's country code |
Parcel Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| weight | double(8,2) | true | Parcel weight in KG |
| width | double(8,2) | false | Parcel width in CM |
| height | double(8,2) | false | Parcel height in CM |
| length | double(8,2) | false | Parcel length in CM |
| parcel_value | double(8,2) | false | Parcel value in account currency |
Quotation Response
Example Response:
{
"status_code": 200,
"request_id": "1770282273531.932b8959-2d5e-4093-a149-86b7c5f8eaa5",
"message": "3 requests success, 0 request error.",
"data": [
{
"status": "success",
"input": {
"sender": {
"postcode": "11900",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "14000",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value": 20,
"weight": 2.5,
"width": 5,
"length": 6,
"height": 7
},
"quotations": [
{
"courier": {
"service_id": "EP-CS05M",
"service_name": "Best Express (Pick Up)",
"courier_id": "EP-CR0DF",
"courier_name": "Best Global Logistics Technology (Malaysia) Sdn. Bhd.",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Best_Express.jpg",
"delivery_duration": null,
"service_tag": [
{
"name": "Service Destinations",
"value": "Domestic"
},
{
"name": "Service Methods",
"value": "Pick Up from Door"
},
{
"name": "Service Methods",
"value": "Deliver to Door"
},
{
"name": "Tracking Quality",
"value": "Excellent"
},
{
"name": "Supported AWB",
"value": "Supported AWB size: A4, A6"
}
]
},
"pricing": {
"currency": "MYR",
"total_amount": "6.95",
"shipment_price": "5.99",
"shipment_tax": "0.36",
"total_features_price": "0.60",
"total_features_tax": "0.00"
},
"features": [
{
"cod": {
"available": false,
"min_cod_amount": "",
"max_cod_amount": "",
"min_cod_charges": "",
"cod_charging_rate": "",
"charges_description": ""
}
},
{
"awb_branding": {
"banner_price": "0.15",
"text_price": "0.10",
"banner_tax": "0.00",
"text_tax": "0.00"
}
},
{
"sms_tracking": {
"sms_price": "0.20",
"custom_sms_price": "0.05",
"remove_ep_branding_price": "0.05",
"sms_tax": "0.00",
"custom_sms_tax": "0.00",
"remove_ep_branding_tax": "0.00"
}
},
{
"email_tracking": {
"email_price": "0.05",
"custom_email_price": "0.05",
"remove_ep_branding_price": "0.05",
"email_tax": "0.00",
"custom_email_tax": "0.00",
"remove_ep_branding_tax": "0.00"
}
},
{
"whatsapp_tracking": {
"whatsapp_price": "0.20",
"whatsapp_tax": "0.00"
}
}
]
}
]
}
]
}
Quotation Response
| Parameter | Type | Description |
|---|---|---|
| status_code | integer | HTTP status code |
| message | string | Response message summary |
| data | array | Array containing quotation results |
Data Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Request status (success/error) |
| input | object | Echo of input parameters |
| quotations | array | Available courier quotations |
Quotation Object
Each quotation contains detailed information about available shipping options:
Courier Information
| Parameter | Type | Description |
|---|---|---|
| service_id | string | Unique service identifier |
| service_name | string | Human-readable service name |
| courier_id | string | Unique courier identifier |
| courier_name | string | Courier company name |
| courier_logo | string | URL to courier logo image |
| delivery_duration | string/null | Expected delivery time |
| service_tag | array | Service categorization tags |
Pricing Information
| Parameter | Type | Description |
|---|---|---|
| currency | string | Currency code (e.g., MYR, USD) |
| total_amount | string | Final total including all fees |
| shipment_price | string | Base shipping price |
| total_features_price | string | Additional features cost |
Service Tags
Service tags provide categorization for different shipping services:
| Tag Name | Possible Values | Description |
|---|---|---|
| Service Label | Standard, Economy, Priority, EXD | Service speed/tier |
| Service Destinations | International, Domestic | Geographic scope |
| Service Methods | Pick Up, Drop-Off | Collection method |
Available Features
The API returns various optional features that can be added to shipments:
Cash on Delivery (COD)
- available: Whether COD is supported
- min_cod_amount/max_cod_amount: COD limits
- charges_description: Additional fee information
Tracking Services
- sms_tracking: SMS notification pricing
- email_tracking: Email notification pricing
- whatsapp_tracking: WhatsApp notification pricing
Branding Options
- awb_branding: Custom branding on shipping labels
- Includes banner and text customization pricing
International Shipping
- ddp_charges: Delivered Duty Paid charges
- Includes import taxes, duties, and handling fees
Code Examples
PHP | Javascripts | Python
async function getShippingQuotes(senderPostcode, receiverPostcode) {
const requestData = {
list: [{
sender: {
postcode: senderPostcode,
subdivision_code: "MY-02",
country: "MY"
},
receiver: {
postcode: receiverPostcode,
subdivision_code: "SG-04",
country: "SG"
},
weight: 0.5,
width: 5,
length: 5,
height: 5,
parcel_value: 50
}]
};
try {
const response = await fetch(
'https://api.easyparcel.com/open_api/2025-06/shipment/quotations',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(requestData)
}
);
const data = await response.json();
if (data.status_code === 200) {
const quotations = data.data[0].quotations;
// Sort by price (lowest first)
quotations.sort((a, b) =>
parseFloat(a.pricing.total_amount) - parseFloat(b.pricing.total_amount)
);
return quotations;
} else {
throw new Error(data.message);
}
} catch (error) {
console.error('Failed to fetch quotations:', error);
throw error;
}
}
<?php
function getShippingQuotes($senderPostcode, $receiverPostcode) {
$requestData = [
'list' => [[
'sender' => [
'postcode' => $senderPostcode,
'subdivision_code' => 'MY-02',
'country' => 'MY'
],
'receiver' => [
'postcode' => $receiverPostcode,
'subdivision_code' => 'SG-04',
'country' => 'SG'
],
'weight' => 0.5,
'width' => 5,
'length' => 5,
'height' => 5,
'parcel_value' => 50
]]
];
$ch = curl_init('https://api.easyparcel.com/open_api/2025-06/shipment/quotations');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('cURL error: ' . curl_error($ch));
}
curl_close($ch);
$data = json_decode($response, true);
if ($data['status_code'] === 200) {
$quotations = $data['data'][0]['quotations'];
// Sort by price (lowest first)
usort($quotations, function($a, $b) {
return floatval($a['pricing']['total_amount']) -
floatval($b['pricing']['total_amount']);
});
return $quotations;
} else {
throw new Exception($data['message']);
}
}
?>
import requests
import json
def get_shipping_quotes(sender_postcode, receiver_postcode):
"""Get shipping quotations for a parcel."""
request_data = {
"list": [{
"sender": {
"postcode": sender_postcode,
"subdivision_code": "MY-02",
"country": "MY"
},
"receiver": {
"postcode": receiver_postcode,
"subdivision_code": "SG-04",
"country": "SG"
},
"weight": 0.5,
"width": 5,
"length": 5,
"height": 5,
"parcel_value": 50
}]
}
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
try:
response = requests.post(
'https://api.easyparcel.com/open_api/2025-06/shipment/quotations',
headers=headers,
data=json.dumps(request_data)
)
data = response.json()
if data['status_code'] == 200:
quotations = data['data'][0]['quotations']
# Sort by price (lowest first)
quotations.sort(key=lambda x: float(x['pricing']['total_amount']))
return quotations
else:
raise Exception(data['message'])
except requests.exceptions.RequestException as e:
raise Exception(f"API request failed: {str(e)}")
Error Handling
Error Response Example:
{
"status_code": 200,
"message": "2 requests success, 1 request error.",
"data": [
{
"status": "error",
"input": {
"sender": {
"postcode": "11900",
"subdivision_code": "MY-07",
"country": "MY"
},
"receiver": {
"postcode": "",
"subdivision_code": "MY-07",
"country": "MY"
},
"parcel_value": 20,
"weight": 2.5,
"width": 5,
"length": 6,
"height": 7
},
"errors": [
"The receiver postcode field is required "
]
}
]
}
The API uses conventional HTTP response codes to indicate success or failure. In addition, the response body contains detailed error information.
HTTP Status Codes
| Code | Meaning |
|---|---|
| 200 | OK -- Request successful (check individual data status) |
| 400 | Bad Request -- Invalid parameters |
| 401 | Unauthorized -- Invalid Oauth 2.0 access token |
| 404 | Not Found -- Endpoint not found |
| 429 | Too Many Requests -- Rate limit exceeded |
| 500 | Internal Server Error -- Server error |
Error Response Structure
| Parameter | Type | Description |
|---|---|---|
| status | string | Always "error" for failed requests |
| input | object | The input that caused the error |
| errors | array | List of specific error messages |
Best Practices for Shipping Quotation
Input Validation
Always validate input parameters before making API requests:
- Verify postcode formats for different countries
- Ensure weight and dimensions are positive numbers
- Check country and subdivision codes against ISO standards
Rate Limiting
The API implements rate limiting to ensure fair usage:
- Batch multiple shipment quotes in a single request when possible
- Implement exponential backoff for 429 responses
- Cache responses when appropriate to reduce API calls
User Experience
To provide the best user experience:
- Sort quotations by price (ascending) by default
- Display courier logos and service names clearly
- Show delivery duration when available
- Allow users to toggle optional features
- Highlight popular or recommended services
Coupon Feature
The coupon feature allows customers to search for available promo codes and apply them during the shipment order submission. This helps users enjoy discounted rates or special benefits based on current promotional campaigns.
Searching for Coupons
Customers can retrieve a list of available coupon codes using the following endpoint:
HTTP Request (Coupon)
GET https://api.easyparcel.com/open_api/2025-06/shipment/get_coupon_list
This will return a list of valid promo codes available to use for the shipment from the user’s account, based on factors such as delivery type, courier, or region.
Coupon Request
Submitting to the Coupon Listing Endpoint based on the submit shipment order endpoint request to get the available coupon for the shipment
Sample Coupon Listing Request:
{
"shipment": [
{
"service_id": "EP-CS05M",
"collection_date": "2025-04-20",
"weight": 2.5,
"height": 5,
"length": 6,
"width": 7,
"item": [
{
"content": "Electronics 2",
"weight": 1.0,
"height": 5,
"length": 6,
"width": 7,
"currency_code": "MYR",
"value": 20,
"quantity": 2
},
{
"content": "Electronics 1",
"weight": 0.5,
"height": 5,
"length": 6,
"width": 7,
"currency_code": "MYR",
"value": 20,
"quantity": 1
}
],
"sender": {
"name": "John Doe",
"company": "ABC Corp",
"phone_number_country_code": "MY",
"phone_number": "1263042201",
"email": "john@easyparcel.com",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"postcode": "11900",
"city": "Lunas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"receiver": {
"name": "Jane Smith",
"company": "XYZ Inc",
"phone_number_country_code": "MY",
"phone_number": "1169641281",
"email": "smith@easyparcel.com",
"address_1": "456 High St",
"address_2": "Floor 2",
"postcode": "14000",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"feature": {
"sms_tracking": true,
"email_tracking": true,
"whatsapp_tracking": true,
"awb_branding": false
}
}
]
}
Coupon Respond
Coupon Listing API - Response Parameters
Sample Respone for the courier listing
{
"status_code": 200,
"message": "1 coupon(s) available",
"data": {
"account_id": 8583757,
"currency_code": "MYR",
"coupons": [
{
"coupon_code": "d1a1764b-9dcd-4d04-9b5d-8fff28c58db4",
"title": "RM2 OFF For New Users Only",
"description": "- Enjoy RM2 OFF on your domestic/international delivery by using this exclusive coupon on EasyParcel. \n- Applicable for all shipment booking on EasyParcel, exclude those orders booked via integrations/API. \n- Valid for one year. \n- Each coupon application will be given a one-off RM2 discount with no minimum spend. \n- This coupon will not be returned when there’s any shipment cancellation. \n- This coupon is strictly not refundable or exchangeable for cash. \n- This coupon will be invalid and will not be replaced once expired. \n- EasyParcel reserves the right to vary and amend any of the above terms and conditions from time to time without prior notice.",
"discounted_amount": "2.00",
"discount_rate": "100.00%",
"valid_from_date": "2026-01-28 13:56:27",
"valid_to_date": "2027-01-28 13:56:27"
}
]
}
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| message | string | Description of the response message |
| data | object | Container for coupon and account details |
data Object
| Parameter | Type | Description |
|---|---|---|
| account_id | int | The EasyParcel account ID |
| currency_code | string | Currency in which the discount is offered (e.g., MYR) |
| coupons | array | List of coupon objects available for use |
coupon Object (Inside coupons array)
| Parameter | Type | Description |
|---|---|---|
| coupon_code | string | Unique identifier for the coupon |
| title | string | Title or name of the coupon campaign |
| description | string | Description or note about the coupon |
| discounted_amount | string | Discount value in currency terms |
| discount_rate | string | Discount in percentage (e.g., "10.00%") |
| valid_from_date | string | Start datetime of coupon validity (UTC format) |
| valid_to_date | string | End datetime of coupon validity (UTC format) |
Applying Coupons
During the order submission process (e.g., /shipment/submit or /ondemand/shipment/submit), customers can apply a valid coupon code by including it in the request body.
To apply coupon just adding the coupon_codes parameters to the request
Sample Field in submit orders:
{
"coupon_codes" :["d1a1764b-9dcd-4d04-9b5d-8fff28c58db4"],
"shipment": [
{
// as per the shipment details
}
]
}
If the coupon is valid and applicable, the discounted amount will be reflected in the final pricing.
Please ensure the coupon is valid and not expired before applying. For additional validation feedback, refer to the response message from the submission endpoint.
Submit Orders
This feature enables users to submit shipment orders. Users are required to fill in the necessary fields to access the shipping service.
HTTP Request (Submit)
POST https://api.easyparcel.com/shipment/submit_orders
Submit Order Request
Request Sample
{
"coupon_codes": [
"d1a1764b-9dcd-4d04-9b5d-8fff28c58db4"
],
"shipment": [
{
"service_id": "EP-CS05M",
"collection_date": "2025-04-20",
"weight": 2.5,
"height": 5,
"length": 6,
"width": 7,
"item": [
{
"content": "Electronics 2",
"weight": 1.0,
"height": 5,
"length": 6,
"width": 7,
"currency_code": "MYR",
"value": 20,
"quantity": 2
},
{
"content": "Electronics 1",
"weight": 0.5,
"height": 5,
"length": 6,
"width": 7,
"currency_code": "MYR",
"value": 20,
"quantity": 1
}
],
"sender": {
"name": "John Doe",
"company": "ABC Corp",
"phone_number_country_code": "MY",
"phone_number": "1263042201",
"email": "john@easyparcel.com",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"postcode": "11900",
"city": "Lunas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"receiver": {
"name": "Jane Smith",
"company": "XYZ Inc",
"phone_number_country_code": "MY",
"phone_number": "1169641281",
"email": "smith@easyparcel.com",
"address_1": "456 High St",
"address_2": "Floor 2",
"postcode": "14000",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"country_code": "MY"
},
"feature": {
"sms_tracking": true,
"email_tracking": true,
"whatsapp_tracking": true,
"awb_branding": false
}
}
]
}
Main Structure
| Parameter | Type | Required | Description |
|---|---|---|---|
| shipment | array | Yes | Array of shipment orders |
Shipment Object
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| service_id | string(10) | Yes | Service Identification number | - |
| collection_date | date | Yes | Date to collect the parcel | Format: YYYY-MM-DD |
| customer_reference_no | string | No | Customer reference number | - |
| weight | double(8,2) | Yes | Weight of the parcel | in KG |
| unit | string | No | Unit of measurement | - |
| height | double(8,2) | Yes | Height of the parcel | in CM |
| length | double(8,2) | Yes | Length of the parcel | in CM |
| width | double(8,2) | Yes | Width of the parcel | in CM |
| item | array | Yes | Items in the parcel | refer to item |
| sender | object | Yes | Origin of the parcel | refer to sender |
| receiver | object | Yes | Destination of the parcel | refer to receiver |
| feature | object | Yes | Additional service features | refer to feature |
Sender
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| name | string | Yes | Sender's Name | - |
| company | string | No | Sender's Company | - |
| phone_number_country_code | string | Yes | ISO 3166-1 Alpha-2 Country code of the Phone number | Example: "MY" |
| phone_number | string | Yes | Sender's phone number | - |
| alternate_phone_number_country_code | string | No | ISO 3166-1 Alpha-2 Country code for alternate phone number | - |
| alternate_phone_number | string | No | Sender's alternate phone number | - |
| string | No | Sender's email | - | |
| address_1 | string | Yes | Sender's address | - |
| address_2 | string | No | Sender's address (continued) | - |
| postcode | string | Yes | Sender's postcode | - |
| city | string | Yes | Sender's city/town | - |
| subdivision_code | string | No | Sender's state/province code | Example: "MY-07" |
| country_code | string(2) | Yes | The origin country of the parcel | Example: "MY" |
| point_code | string | No | A unique identifier for sender location | - |
Receiver
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| name | string | Yes | Receiver's Name | - |
| company | string | No | Receiver's Company | - |
| phone_number_country_code | string | Yes | ISO 3166-1 Alpha-2 Country code of the Phone number | Example: "MY" |
| phone_number | string | Yes | Receiver's phone number | - |
| alternate_phone_number_country_code | string | No | ISO 3166-1 Alpha-2 Country code for alternate phone number | - |
| alternate_phone_number | string | No | Receiver's alternate phone number | - |
| string | No | Receiver's email | - | |
| address_1 | string | Yes | Receiver's address | - |
| address_2 | string | No | Receiver's address (continued) | - |
| postcode | string | Yes | Receiver's postcode | - |
| city | string | Yes | Receiver's city/town | - |
| subdivision_code | string | No | Receiver's state/province code | Example: "MY-07" |
| country_code | string(2) | Yes | The destination country of the parcel | Example: "MY" |
| point_code | string | No | A unique identifier for receiver location | - |
Feature
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| sms_tracking | boolean | No | Enable SMS tracking notifications | Default: false |
| email_tracking | boolean | No | Enable email tracking notifications | Default: false |
| whatsapp_tracking | boolean | No | Enable WhatsApp tracking notifications | Default: false |
| awb_branding | object | No | Airway bill branding | refer to awb_branding |
| cod | object | No | Cash on Delivery | refer to cod |
awb_branding
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| enable | boolean | Yes | To enable or disable Airways Bills Branding | - |
cod
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| cod_amount | double | Yes | Cash on Delivery amount | - |
| cod_currency_code | string | Yes | Currency code for COD transaction | Example: "MYR" |
Items
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| content | string | Yes | Description of the content | - |
| weight | double(8,2) | Yes | Weight of the item | in KG |
| height | double(8,2) | Yes | Height of the item | in CM |
| length | double(8,2) | Yes | Length of the item | in CM |
| width | double(8,2) | Yes | Width of the item | in CM |
| currency_code | string(3) | Yes | The currency code of the item value | Example: "MYR" |
| value | double(8,2) | Yes | Value of the item | - |
| quantity | int | Yes | The item quantity | - |
Sumbit Order Response
Successful Response Example
{
"status_code": 200,
"message": "1 request success, 0 request error.",
"data": [
{
"order_details": {
"order_number": "EI-2601-PRNN4",
"account_id": 8583757
},
"pricing_breakdown": {
"currency_code": "MYR",
"total_order_amount": "6.44",
"total_paid_amount": "6.44",
"total_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"shipments": [
{
"status": "success",
"shipment_number": "ES-2601-3MMYQ",
"courier_service": null,
"courier": "Best Global Logistics Technology (Malaysia) Sdn. Bhd.",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/Best_Express.jpg",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"weight": 2.5,
"height": 5,
"length": 6,
"width": 7,
"pricing_breakdown": {
"currency_code": "MYR",
"total_paid_amount": "6.44",
"shipment_price": "5.99",
"shipment_tax_amount": "0.00",
"total_features_price": "0.45",
"total_features_tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1263042201",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "john@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas",
"subdivision_code": "MY-07",
"postcode": "11900",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1169641281",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "smith@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas",
"subdivision_code": "MY-07",
"postcode": "14000",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics 2",
"weight": 1,
"height": 5,
"length": 6,
"width": 7,
"currency_code": "MYR",
"value": 20,
"quantity": 2
},
{
"content": "Electronics 1",
"weight": 0.5,
"height": 5,
"length": 6,
"width": 7,
"currency_code": "MYR",
"value": 20,
"quantity": 1
}
],
"features": {
"cod": null,
"insurance_purchase": [
{
"service_name": "Insure Plus",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
},
{
"service_name": "Basic Coverage",
"insurance_cover_notice": "for lost or damage",
"currency_code": "MYR",
"charge_amount": "0.00",
"total_amount": "0.00",
"tax_amount": "0.00"
}
],
"shipment_tracking_whatsapp": {
"message": "Hey there! Your order from John Doe is ready to be collected for delivery soon!\n\nTracking no: null",
"phone_country_code": "+60",
"phone_number": "1169641281",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_sms": {
"message": "Your order from John Doe is ready & trackable once courier scans in. Track at EasyParcel with [Placeholder Trackin..] -Powered by EasyParcel",
"phone_country_code": "+60",
"phone_number": "1169641281",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.20",
"tax_amount": "0.00"
},
"shipment_tracking_email": {
"email": "smith@easyparcel.com",
"currency_code": "MYR",
"total_amount": "0.00",
"price": "0.05",
"tax_amount": "0.00"
},
"shipment_awb_branding": null
}
}
]
}
]
}
Successful Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of order results |
Order Details Object
| Parameter | Type | Description |
|---|---|---|
| order_details | object | Details about the order |
| pricing | object | Pricing information |
| shipments | array | Array of shipment details |
Order Details
| Parameter | Type | Description |
|---|---|---|
| order_number | string | Order number of the shipment batch |
| account_id | string | Account ID used for the shipment |
Pricing
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used for the shipment |
| total_amount | string | Total cost of all shipments |
| total_tax_amount | string | Total tax amount |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the shipment request |
| shipment_number | string | The unique number of the shipment |
| courier_service | string | Service type selected for shipment |
| courier | string | Name of the courier service |
| collection_date | string | Collection date of the parcel |
| awb_url | string | URL to access the airway bill |
| awb_number | string | The airway bill number |
| tracking_url | string | URL to track the parcel |
| weight | double | Weight of the shipment |
| height | double | Height of the shipment |
| length | double | Length of the shipment |
| width | double | Width of the shipment |
| pricing_breakdown | object | Detailed pricing breakdown |
| sender | object | Sender details |
| receiver | object | Receiver details |
| shipment_items | array | Items in the shipment |
| features | object | Enabled features details |
Pricing Breakdown
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used for the shipment |
| total_order_amount | string | Total cost of the shipment |
| shipment_price | string | Base price of the shipment |
| total_tax_amount | string | Tax amount |
| total_features_price | string | Total price for additional features |
| coupon_redeemed | string | Total amonut deducted using coupon_redeemed |
Features
| Parameter | Type | Description |
|---|---|---|
| cod | object | Cash on Delivery details (if enabled) |
| shipment_tracking_whatsapp | object | WhatsApp tracking details (if enabled) |
| shipment_tracking_sms | object | SMS tracking details (if enabled) |
| shipment_tracking_email | object | Email tracking details (if enabled) |
Error Response
For failed requests, the response includes error details:
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code indicating error |
| message | string | Error summary message |
| data | array | Array of shipment request details |
| errors | array | List of specific error messages |
Error Response Example
{
"status_code": 200,
"message": "0 requests success, 1 request error.",
"data": [
{
"order_details": {
"account_id": "8583757"
},
"pricing": {
"currency_code": "MYR",
"total_amount": "0.00",
"total_tax_amount": "0.00"
},
"shipments": [
{
"status": "error",
"collection_date": "",
"weight": "",
"height": "",
"length": "",
"width": "",
"sender": {
"point_code": null,
"name": "John Doe",
"phone_number_country_code": "MY",
"phone_number": "1263042201",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "john@easyparcel.com",
"company_name": "ABC Corp",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "",
"subdivision_code": "",
"postcode": "",
"country_code": "MY"
},
"receiver": {
"point_code": null,
"name": "Jane Smith",
"phone_number": "1169641281",
"phone_number_country_code": "MY",
"alternate_phone_number": null,
"alternate_phone_number_country_code": null,
"email": "smith@easyparcel.com",
"company_name": "XYZ Inc",
"address1": "456 High St",
"address2": "Floor 2",
"city": "",
"subdivision_code": "",
"postcode": "14000",
"country_code": "MY"
},
"shipment_items": [
{
"content": "Electronics 2",
"weight": 1,
"height": 5,
"length": 6,
"width": 7,
"currency_code": "MYR",
"value": 20,
"quantity": 2,
"insurance_purchase": null
},
{
"content": "Electronics 1",
"weight": 0.5,
"height": 5,
"length": 6,
"width": 7,
"currency_code": "MYR",
"value": 20,
"quantity": 1,
"insurance_purchase": null
}
],
"features": {
"cod": false,
"shipment_tracking_whatsapp": false,
"shipment_tracking_sms": false,
"shipment_tracking_email": false
},
"errors": [
"The sender postcode field is required "
]
}
]
}
]
}
Shipment Listing
This endpoint allows users to retrieve a list of shipments with optional filtering parameters. Results are sorted by the latest shipments first.
HTTP Request (Listing)
POST https://api.easyparcel.com/open_api/2025-06/shipment/list
Listing Request
Pagination
This API uses cursor-based pagination with the before_shipment_number parameter. To retrieve the next page of results:
- Make your initial request with desired filters and
limit - Note the
shipment_numberof the last shipment in the response - Use that shipment number as
before_shipment_numberin your next request to get older shipments
Since results are sorted newest first, each subsequent request returns the next set of older shipments.
Request Sample
{
"limit": 3,
"before_shipment_number": "ES-2601-3MMYQ",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-20"
}
Note: You can submit a request without any filters, but the maximum limit is 250 shipments per API call. Results are sorted with the latest shipments first.
Main Structure
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| limit | int | No | Maximum number of results to return | Default: 10, Maximum: 250 |
| before_shipment_number | string | No | Get shipments before this shipment number | For pagination purposes |
| shipment_status_code | string | No | Filter by shipment status code | Example: "7" for "Schedule In Arrangement" |
| date_from | date | No | Start date for filtering shipments | Format: YYYY-MM-DD |
| date_to | date | No | End date for filtering shipments | Format: YYYY-MM-DD |
Returned Parameters
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"shipment_number": "ES-2504-XYQUA",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-22 16:00:00",
"courier": {
"service_type": "Mystery Saver",
"courier_id": "EP-CR0AT",
"service_id": "EP-CS0AT",
"courier_name": "TracX Logis Pte. Ltd",
"courier_short_name": "TRACX LOGIS",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "testSG",
"email": "ep@easyparcel.com",
"contact": "SG88888888",
"alternative_contact": 0,
"address1": "test sg",
"subdivision_code": "SG-04",
"postal_code": "409015",
"country": "SG"
},
"receiver_details": {
"name": "testSG",
"email": "ep@easyparcel.com",
"contact": "SG88888888",
"alternative_contact": 0,
"subdivision_code": "SG-04",
"postal_code": "409015",
"country": "SG"
},
"pricing": {
"currency_code": "MYR",
"price": 16.99
}
},
{
"shipment_number": "ES-2504-B4H35",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-22 16:00:00",
"courier": {
"service_type": "Mystery Saver",
"courier_id": "EP-CR0AT",
"service_id": "EP-CS0AT",
"courier_name": "TracX Logis Pte. Ltd",
"courier_short_name": "TRACX LOGIS",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "testSG",
"email": "ep@easyparcel.com",
"contact": "SG88888888",
"alternative_contact": 0,
"address1": "test sg",
"subdivision_code": "SG-04",
"postal_code": "409015",
"country": "SG"
},
"receiver_details": {
"name": "testSG",
"email": "ep@easyparcel.com",
"contact": "SG88888888",
"alternative_contact": 0,
"subdivision_code": "SG-04",
"postal_code": "409015",
"country": "SG"
},
"pricing": {
"currency_code": "MYR",
"price": 16.99
}
},
{
"shipment_number": "ES-2504-4XMAY",
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"coll_date": "2025-04-22 16:00:00",
"courier": {
"service_type": "Mystery Saver",
"courier_id": "EP-CR0AT",
"service_id": "EP-CS0AT",
"courier_name": "TracX Logis Pte. Ltd",
"courier_short_name": "TRACX LOGIS",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/"
},
"sender_details": {
"name": "testSG",
"email": "ep@easyparcel.com",
"contact": "SG88888888",
"alternative_contact": 0,
"address1": "test sg",
"subdivision_code": "SG-04",
"postal_code": "409015",
"country": "SG"
},
"receiver_details": {
"name": "testSG",
"email": "ep@easyparcel.com",
"contact": "SG88888888",
"alternative_contact": 0,
"subdivision_code": "SG-04",
"postal_code": "409015",
"country": "SG"
},
"pricing": {
"currency_code": "MYR",
"price": 16.99
}
}
],
"pagination": {
"next_page_token": "eyJsYXN0X2lkIjoyNTg2OSwiZmlsdGVycyI6eyJ0cmFja2luZ19zdGF0dXMiOiI3IiwiZGF0ZV9mcm9tIjoiMjAyNS0wNC0wMSAwMDowMDowMCIsImRhdGVfdG8iOiIyMDI1LTA0LTIwIDIzOjU5OjU5In19",
"next_shipment_number": "ES-2504-4XMAY",
"has_more": true,
"limit": 3,
"filter_applied": {
"tracking_status": "7",
"date_from": "2025-04-01 00:00:00",
"date_to": "2025-04-20 23:59:59",
"tracking_status_code": "7"
}
}
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of shipment objects |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| shipment_number | string | Unique shipment identifier |
| awb | string | Airway bill number (null if not assigned) |
| shipment_status_code | int | Status code of the shipment |
| shipment_status | string | Human-readable shipment status |
| coll_date | string | Collection date and time |
| courier | object | Courier information |
| sender_details | object | Sender information |
| receiver_details | object | Receiver information |
| pricing | object | Pricing information |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| service_type | string | Type of courier service |
| courier_id | string | Unique identifier for the courier |
| service_id | string | Unique identifier for the service |
| courier_name | string | Full name of the courier company |
| courier_short_name | string | Short name of the courier company |
| courier_logo | string | URL to the courier logo image |
Sender Details Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the sender |
| string | Email address of the sender | |
| contact | string | Contact number with country code |
| alternative_contact | string/int | Alternative contact number (0 if none) |
| address1 | string | First line of the sender's address |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
Receiver Details Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the receiver |
| string | Email address of the receiver | |
| contact | string | Contact number with country code |
| alternative_contact | string/int | Alternative contact number (0 if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
Pricing Object
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency code for the price |
| price | double | Price of the shipment |
Common Status Code
| Status Code | Description |
|---|---|
| 200 | Successful request |
| 400 | Bad request (missing or invalid parameters) |
| 401 | Unauthorized (invalid authentication) |
| 404 | Not found (no shipments matching the criteria) |
| 500 | Server error |
Usage Notes (Listing)
- For pagination, use the
before_shipment_numberparameter with the last shipment number from the previous request. - Date filters (
date_fromanddate_to) filter by shipment collection date. - Results are always sorted by newest first.
- When no filters are applied, the API returns the most recent shipments up to the specified limit.
Shipment Details
This endpoint allows users to retrieve detailed information about a specific shipment using its shipment number.
HTTP Request (Detail)
POST https://api.easyparcel.com/open_api/2025-06/shipment/details
Shipment Details Request
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| shipment_number | string | Yes | Shipment number to query | Format: ES-YYMM-XXXXX |
Request Sample
{
"shipment_number": "ES-2601-3MMYQ"
}
Shipment Details Response
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"shipment_number": "ES-2601-3MMYQ",
"order_number": "EI-2601-PRNN4",
"shipment_details": {
"weight": 2.5,
"height": 5,
"length": 6,
"width": 7,
"shipment_status_code": 7,
"shipment_status": "Schedule In Arrangement",
"parcels_value": "40",
"insurance_label": null,
"awb_number": null,
"awb_url": null,
"tracking_url": null,
"coll_date": "2025-04-20 00:00:00"
},
"parcel_content": [
{
"content": "Electronics 2",
"weight": "1.00000",
"height": 5,
"length": 6,
"width": 7,
"value": 20,
"currency_code": "MYR"
},
{
"content": "Electronics 1",
"weight": "0.50000",
"height": 5,
"length": 6,
"width": 7,
"value": 20,
"currency_code": "MYR"
}
],
"courier": {
"courier_name": "Best Global Logistics Technology (Malaysia) Sdn. Bhd.",
"service_id": "EP-CR0DF",
"courier_id": "EP-CR0DF",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/",
"service_types": "Best Express (Pick Up)"
},
"sender": {
"name": "John Doe",
"company_name": "ABC Corp",
"email": "john@easyparcel.com",
"contact": "+601263042201",
"alternative_contact": null,
"subdivision_code": "MY-07",
"postal_code": "11900",
"country": "MY",
"address1": "123 Main St",
"address2": "Apt 4B",
"city": "Lunas"
},
"receiver": {
"name": "Jane Smith",
"company_name": "XYZ Inc",
"email": "smith@easyparcel.com",
"contact": "+601169641281",
"alternative_contact": null,
"subdivision_code": "MY-07",
"postal_code": "14000",
"country": "MY",
"address1": "456 High St",
"address2": "Floor 2",
"city": "Bayan Lepas"
},
"pricing": {
"currency_code": "MYR",
"total_price": "0.00",
"shipment_price": "5.99",
"tax_price": "0.00",
"sms_notification": "0.00",
"email_notification": "0.00",
"whatsapp_notification": "0.00",
"awb_branding": null,
"insurance": null,
"ddp": null
}
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array containing the shipment details |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| shipment_number | string | Unique shipment identifier |
| order_number | string | Order number associated with shipment |
| shipment_details | object | Detailed shipment information |
| parcel_content | array | List of items in the shipment |
| courier | object | Courier service information |
| sender | object | Sender information |
| receiver | object | Receiver information |
| pricing | object | Detailed pricing breakdown |
Shipment Details Object
| Parameter | Type | Description |
|---|---|---|
| weight | double | Total weight of the shipment |
| height | double | Height of the shipment |
| length | double | Length of the shipment |
| width | double | Width of the shipment |
| shipment_status_code | int | Status code of the shipment |
| shipment_status | string | Human-readable shipment status |
| parcels_value | string | Total value of items in the shipment |
| insurance_label | string | Insurance information (null if not insured) |
| awb_number | string | Airway bill number (null if not assigned) |
| tracking_url | string | URL to track the shipment |
| awb_url | string | URL to access the airway bill |
| coll_date | string | Collection date and time |
Parcel Content Object
| Parameter | Type | Description |
|---|---|---|
| content | string | Description of the item |
| weight | string | Weight of the item |
| height | int | Height of the item |
| length | int | Length of the item |
| width | int | Width of the item |
| value | double | Monetary value of the item |
| currency_code | string | Currency code for the item value |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| courier_name | string | Full name of the courier company |
| service_id | string | Unique identifier for the service |
| courier_id | string | Unique identifier for the courier |
| courier_logo | string | URL to the courier logo image |
| service_types | string | Type of courier service |
Sender Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the sender |
| company_name | string | Company name of the sender |
| string | Email address of the sender | |
| contact | string | Contact number with country code |
| alternative_contact | string | Alternative contact number (null if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
| address1 | string | First line of the sender's address |
| address2 | string | Second line of the sender's address |
| city | string | City/town of the sender |
Receiver Object
| Parameter | Type | Description |
|---|---|---|
| name | string | Name of the receiver |
| company_name | string | Company name of the receiver |
| string | Email address of the receiver | |
| contact | string | Contact number with country code |
| alternative_contact | string | Alternative contact number (null if none) |
| subdivision_code | string | State/province code (null if not provided) |
| postal_code | string | Postal/ZIP code |
| country | string | Country code |
| address1 | string | First line of the receiver's address |
| address2 | string | Second line of the receiver's address |
| city | string | City/town of the receiver |
Pricing Object
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency code for all pricing |
| total_price | string | Total price of the shipment |
| shipment_price | string | Base shipping cost |
| tax_price | string | Tax amount |
| sms_notification | string | Price for SMS notification (null if not enabled) |
| email_notification | string | Price for email notification (null if not enabled) |
| whatsapp_notification | string | Price for WhatsApp notification (null if not enabled) |
| awb_branding | string | Price for AWB branding (null if not enabled) |
| insurance | string | Price for insurance (null if not purchased) |
| ddp | string | Delivered Duty Paid fee (null if not applicable) |
Error Response
If the shipment is not found or the request is invalid, the API will return an error response:
{
"status_code": 400,
"message": "No Order with shipment_number ES-2601-3MMY found from this account",
"data": []
}
Usage Notes (Detail)
- This endpoint retrieves comprehensive information about a single shipment.
- The shipment number must be in the format ES-YYMM-XXXXX (e.g., ES-2504-3WYYP).
- Values for various fields like awb_number, insurance_label, etc. may be null if they aren't applicable to the shipment's current status.
- Pricing details provide a complete breakdown of all charges associated with the shipment.
- The tracking_url can be used to provide tracking information to customers.
Cancel Shipments
This endpoint allows users to cancel one or more shipments. Users can provide a list of shipment numbers along with cancellation remarks.
HTTP Request (Cancel)
POST https://api.easyparcel.com/open_api/2025-06/shipment/cancel
Cancel Request Parameters
Request Sample
{
"cancel_list": [
{
"shipment_number": "ES-2601-3MMYQ",
"remark": "test"
}
]
}
Main Structure
| Parameter | Type | Required | Description |
|---|---|---|---|
| cancel_list | array | Yes | List of shipments to cancel |
Cancel Item Object
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| shipment_number | string | Yes | Shipment number to cancel | Format: ES-YYMM-XXXXX |
| remark | string | Yes | Reason for cancellation | - |
Cancel Return Parameters
Successful Response Example
{
"status_code": 200,
"message": "1 requests success, 0 request error.",
"data": [
{
"status": "success",
"message": "Order Cancelled",
"shipment_number": "ES-2601-3MMYQ"
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Summary message (e.g., "2 requests success, 0 request error.") |
| data | array | Array of cancellation results |
Cancellation Result Object
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the cancellation request ("success" or "error") |
| message | string | Detailed message about the cancellation result |
| shipment_number | string | The shipment number that was processed |
Error Response Example
{
"status_code": 200,
"message": "0 requests success, 1 request error.",
"data": [
{
"status": "error",
"message": "Shipment Already Cancelled",
"shipment_number": "ES-2601-3MMYQ"
}
]
}
Usage Notes (Cancellation)
- You can cancel multiple shipments in a single request by including them in the
cancel_listarray. - Only shipments that have not yet been processed by the courier can be cancelled.
- Each shipment in the
cancel_listwill be processed independently - some may succeed while others fail. - A successful response (
status_code: 200) does not guarantee all shipments were cancelled. Always check individual status values in the data array. - Cancellation remarks are mandatory and should provide a reason for the cancellation.
- The API returns a 200 status code even when all cancellations fail, so always check the message and data fields.
Couriers List
This endpoint allows users to retrieve a list of available courier services for a specific country.
HTTP Request (Courier List)
GET https://api.easyparcel.com/open_api/2025-06/courier/list
Courier List Request
Request Sample
{
"country_code": "MY"
}
Requested Parameters
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| country_code | string | Yes | Country code to filter by | Example: "MY" for Malaysia |
Courier List Response
Response Sample
{
"status_code": 200,
"message": "success",
"data": [
{
"courier_id": "EP-CR0I",
"uuid": "c473d2c4-ab06-456a-9886-54a5c3d25c91",
"courier_name": "SF Global Express",
"short_name": "SF Express",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel/Public/source/general/img/couriers/SF_Express.jpg",
"country": "Malaysia"
},
{
"courier_id": "EP-CR0G",
"uuid": "01e1cad9-d20a-411f-8c71-a1b3ed722b3f",
"courier_name": "Aramex",
"short_name": "Aramex",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel/Public/source/general/img/couriers/Aramex.jpg",
"country": "Malaysia"
},
{
"courier_id": "EP-CR0AO",
"uuid": "5e6a0ee2-5d6d-499d-8994-bd71a82730b9",
"courier_name": "Teleport Commerce Malaysia Sdn Bhd",
"short_name": "Teleport",
"courier_logo": "https://s3-ap-southeast-1.amazonaws.com/easyparcel/Public/source/general/img/couriers/Teleport.jpg",
"country": "Malaysia"
}
]
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | array | Array of available courier services |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| courier_id | string | Unique identifier for the courier |
| uuid | string | Universal unique identifier |
| courier_name | string | Full name of the courier company |
| short_name | string | Abbreviated name of the courier |
| courier_logo | string | URL to the courier's logo image |
| country | string | Country where the courier operates |
Error Response
If an invalid country code is provided, the API will return an error response:
{
"status_code": 400,
"message": "Invalid country code",
"data": []
}
Supported Country Codes
| Country Code | Country Name |
|---|---|
| MY | Malaysia |
| SG | Singapore |
| TH | Thailand |
| ID | Indonesia |
| CN | China |
| PH | Philippines |
| VN | Vietnam |
| AU | Australia |
| US | United States |
| CA | Canada |
| GB | United Kingdom |
Common Status Codes
| Status Code | Description |
|---|---|
| 200 | Successful request |
| 400 | Bad request (invalid country code) |
| 401 | Unauthorized (invalid authentication) |
| 500 | Server error |
Usage Notes (Courier List)
- The
courier_idvalue returned by this endpoint is used in other API calls, such as when submitting a shipment order. - Courier availability may vary by country. Use the appropriate country code to get relevant results.
- The response includes full company names and shortened display names for each courier.
- Courier logos can be used in your application to display carrier branding.
- There may be multiple entries for the same courier company if they offer different types of services.
OnDemand Shipping
OnDemand API Flow Overview
This document provides a visual representation of the different flows and processes available through the EasyParcel API.
Ondemand Workflow Diagram
graph TD
B[[Shipping]]
%% Shipping Flow
B --> B1[[Order Flow]]
B --> B2[[Cancel Flow]]
%% Order Flow
B1 --> B11[Get Ondemand Quotation]
B11 --> B12[Get Cuopon Listing]
B12 --> B13[Submit Order]
%% Cancel Flow
B2 --> B23[Cancel Orders]
OnDemand Quotation
OnDemand Quotation Overview
This feature enables users to obtain on-demand shipment quotations from all courier companies available on the EasyParcel platform. Users need to provide sender and receiver addresses and waypoint information to retrieve shipment quotations. The response includes available courier services, transportation type, pricing details, and optional add-on features.
HTTP Request (OnDemand Quotation)
POST https://api.easyparcel.com/open_api/2025-06/ondemand/quotations
OnDemand Quotation Request Parameters
Request Sample
{
"schedule_pickup_date": "2024-11-30",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"type": "pickup"
},
{
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia",
"type": "dropoff"
}
]
}
Main Structure
| Parameter | Type | Required | Description | Remarks |
|---|---|---|---|---|
| schedule_pickup_date | string | No | Scheduled pickup date (YYYY-MM-DD) | - |
| schedule_pickup_time | string | No | Scheduled pickup time (HH:MM:SS) | - |
| timezone | string | No | Pickup timezone | - |
| waypoint | array | Yes | List of pickup and dropoff points | Minimum 2 required |
| waypoint[*].coordinates.latitude | numeric | Yes | Location latitude | - |
| waypoint[*].coordinates.longitude | numeric | Yes | Location longitude | - |
| waypoint[*].address | string | No | Full address of the location | - |
| waypoint[*].type | string | Yes | Either pickup or dropoff |
- |
OnDemand Quotation Response Parameters
Sample Response
Refer to the full JSON response you provided in your message for all details on courier quotations including Lalamove and PandaGo examples with their respective vehicle types, prices, weight and dimension limits.
{
"status_code": 200,
"message": "",
"data": [
{
"status": "success",
"input": {
"schedule_pickup_date": "2024-11-30",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"type": "pickup"
},
{
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia",
"type": "dropoff"
}
]
},
"quotations": [
{
"metadata": {
"quotationId": "3419574442106515759"
},
"courier": {
"service_id": "EP-CS0I",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Car",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "40kg",
"dimension": "50cmx50cmx50cm"
},
"pricing": {
"total_amount": 7.76,
"shipping_price": "7.76",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3419574389920977479"
},
"courier": {
"service_id": "EP-CS0F",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Bike",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "10kg",
"dimension": "30cmx30cmx30cm"
},
"pricing": {
"total_amount": 5.88,
"shipping_price": "5.88",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3419575014201192602"
},
"courier": {
"service_id": "EP-CS09",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "4X4",
"durations": "5mins",
"parcel_type_support": "Ideal for small fridge, washing machine, bike, 1-seater sofa",
"weight_limit": "250kg",
"dimension": "120cmx90cmx90cm"
},
"pricing": {
"total_amount": 27.06,
"shipping_price": "27.06",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3419574442106515787"
},
"courier": {
"service_id": "EP-CS05",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Large Van",
"durations": "5mins",
"parcel_type_support": "Ideal for washing machine, sofa, treadmill , large parcels",
"weight_limit": "800kg",
"dimension": "270cmx130cmx120cm"
},
"pricing": {
"total_amount": 57.65,
"shipping_price": "57.65",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3419574685082538445"
},
"courier": {
"service_id": "EP-CS0G",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Lorry 10-ft",
"durations": "5mins",
"parcel_type_support": "Ideal for queen size bed, fridge, 3-seater sofa, wardrobe",
"weight_limit": "1000kg",
"dimension": "290cmx150cmx150cm"
},
"pricing": {
"total_amount": 78.82,
"shipping_price": "78.82",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3419574138078196210"
},
"courier": {
"service_id": "EP-CS0M",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Lorry 14-ft",
"durations": "5mins",
"parcel_type_support": "Ideal for king size bed, large fridge, 3-seater sofa, wardro",
"weight_limit": "2500kg",
"dimension": "420cmx200cmx200cm"
},
"pricing": {
"total_amount": 125.29,
"shipping_price": "125.29",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": "3419574270735643636"
},
"courier": {
"service_id": "EP-CS0Y",
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"transport": {
"transportation_type": "Van",
"durations": "5mins",
"parcel_type_support": "Ideal for small fridge, washing machine, bike, 1-seater sofa",
"weight_limit": "500kg",
"dimension": "170cmx100cmx120cm"
},
"pricing": {
"total_amount": 45.88,
"shipping_price": "45.88",
"tax_amount": 0,
"currency": "MYR"
}
},
{
"metadata": {
"quotationId": null
},
"courier": {
"service_id": "EP-CS0R",
"courier_name": "PandaGo",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/pandaGo_pink.png"
},
"transport": {
"transportation_type": "Bike",
"durations": "5mins",
"parcel_type_support": "Parcel",
"weight_limit": "15kg",
"dimension": "43cmx39cmx42cm"
},
"pricing": {
"total_amount": 7.06,
"shipping_price": "7.06",
"tax_amount": 0,
"currency": "MYR"
}
}
]
}
]
}
Main Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code |
| message | string | Status message |
| data | array | List of quotations with metadata |
Data Object Structure
| Parameter | Type | Description |
|---|---|---|
| status | string | Status of the request |
| input | object | Echo of submitted input |
| quotations | array | List of courier quotations |
Quotation Entry Structure
| Section | Parameter | Type | Description |
|---|---|---|---|
| metadata | quotationId | string | Unique quotation ID |
| courier | service_id | string | Service ID |
| courier_name | string | Courier name | |
| img_courier | string | Courier logo URL | |
| transport | transportation_type | string | Transport type (e.g., Bike, Car) |
| durations | string | Estimated delivery time | |
| parcel_type_support | string | Parcel suitability description | |
| weight_limit | string | Weight limit | |
| dimension | string | Max parcel dimension | |
| pricing | total_amount | string | Quotation price |
| currency | string | Currency (e.g., MYR) |
Sample Error Response
{
"status_code": 200,
"message": "0 requests success, 3 request error.",
"data": [
{
"status": "error",
"input": { ... },
"errors": [
"The receiver postcode field is required"
]
},
]
}
OnDemand Quotation Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (requests)
const requestData = {
schedule_pickup_date: "2024-11-30",
schedule_pickup_time: "11:48:35",
timezone: "Asia/Kuala_Lumpur",
waypoint: [
{ type: "pickup", coordinates: { latitude: 5.34, longitude: 100.28 } },
{ type: "dropoff", coordinates: { latitude: 5.32, longitude: 100.28 } }
]
};
fetch('https://api.easyparcel.com/open_api/2025-06/ondemand/quotations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify(requestData)
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$data = [
"schedule_pickup_date" => "2024-11-30",
"schedule_pickup_time" => "11:48:35",
"timezone" => "Asia/Kuala_Lumpur",
"waypoint" => [
["type" => "pickup", "coordinates" => ["latitude" => 5.34, "longitude" => 100.28]],
["type" => "dropoff", "coordinates" => ["latitude" => 5.32, "longitude" => 100.28]]
]
];
$ch = curl_init('https://api.easyparcel.com/open_api/2025-06/ondemand/quotations');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = 'https://api.easyparcel.com/open_api/2025-06/ondemand/quotations'
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
data = {
"schedule_pickup_date": "2024-11-30",
"schedule_pickup_time": "11:48:35",
"timezone": "Asia/Kuala_Lumpur",
"waypoint": [
{"type": "pickup", "coordinates": {"latitude": 5.34, "longitude": 100.28}},
{"type": "dropoff", "coordinates": {"latitude": 5.32, "longitude": 100.28}}
]
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for OnDemand Quotation
- Input Validation – Validate all fields before API call.
- Sorting Quotations – Sort by total amount for better user experience.
- Optional Features – Allow users to toggle extras like insurance or SMS alerts.
- Display Info – Always show courier logos, transport type, and delivery time.
OnDemand Order Submission
This guide explains how to submit an on-demand shipment order with and without applying a coupon, and the structure of the response received.
HTTP Request (OnDemand Submit Order)
POST https://api.easyparcel.com/ondemand/order
OnDemand Submit Order Request
Request Sample
{
"coupon_codes":["dfa5109a-2f35-427e-8482-9b0ab65c323f"],
"origin_country": "MY",
"ondemand_service_id": "EP-CS0F",
"schedule_pickup_date": "2024-11-30",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3419574389920977479"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "1278491622",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Assis",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oren",
"email": "oren@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
| Parameter | Type | Required | Description |
|---|---|---|---|
| coupon_codes | string | Optional | Apply coupon codes to get further discount |
| ondemand_service_id | string | Yes | ID of the selected on-demand service |
| origin_country | string | Yes | ISO 3166-1 alpha-2 country code |
| schedule_pickup_date | string | Optional | Date of pickup (YYYY-MM-DD) |
| schedule_pickup_time | string | Optional | Time of pickup (HH:MM:SS) |
| time_zone | string | Optional | Time zone of the pickup schedule |
| metadata | object | Yes | Additional metadata, e.g. quotationId |
| waypoint | array | Yes | Array of pickup and dropoff points |
| waypoint[*].point | numeric | Yes | Sequence index (e.g., 0 = pickup, 1 = dropoff) |
| waypoint[*].type | string | Yes | Type of stop; must be "pickup" or "dropoff" |
| waypoint[*].coordinates.latitude | numeric | Yes | Latitude of the location |
| waypoint[*].coordinates.longitude | numeric | Yes | Longitude of the location |
| waypoint[*].item | array | Yes | Items associated with the waypoint |
| waypoint[].item[].quantity | string | Yes | Quantity of the item |
| waypoint[].item[].description | string | Optional | Description of the item |
| waypoint[].item[].dimensions.height | string | Yes | Height of the item (in cm) |
| waypoint[].item[].dimensions.width | string | Yes | Width of the item (in cm) |
| waypoint[].item[].dimensions.length | string | Yes | Length of the item (in cm) |
| waypoint[].item[].dimensions.weight | string | Yes | Weight of the item (in kg) |
| waypoint[*].shipment_info.name | string | Yes | Name of the sender/receiver |
| waypoint[*].shipment_info.email | string | Optional | Email address |
| waypoint[*].shipment_info.phone_number_country_code | string | Yes | Phone number country code (e.g., MY) |
| waypoint[*].shipment_info.phone_number | string | Yes | Phone number |
| waypoint[*].shipment_info.address | string | Yes | Full address |
| waypoint[*].remark | string | Optional | Any additional notes or instructions |
OnDemand Submit Order Response
Sample Response
{
"status_code": 200,
"message": "Success",
"data": {
"booking_id": "EOD-156",
"ondemand_service_id": "EP-CS0F",
"order_number": "3419590051796054588",
"tracking_url": "https://share.lalamove.com/?MY100260130112008683410020045182237&lang=en_MY&sign=9fcf473c8fa4992ef076bb862441f6a0&source=api_wrapper",
"courier": {
"service_id": 4,
"courier_name": "Lalamove",
"img_courier": "https://s3-ap-southeast-1.amazonaws.com/easyparcel-static/Public/source/general/img/couriers/lalamove.svg"
},
"pricing_breakdown": {
"currency_code": "MYR",
"total_order_amount": "5.88",
"total_paid_amount": "5.88",
"shipment_amount": "5.88",
"tax_amount": "0.00",
"coupon_redeemed": "0.00"
},
"shipment": {
"origin_country": "MY",
"ondemand_service_id": "EP-CS0F",
"schedule_pickup_date": "2024-11-30",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3419574389920977479"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "1278491622",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Assis",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oren",
"email": "oren@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
}
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code (e.g., 200) |
| message | string | Success or error message |
| data | object | Contains booking details and shipment info |
Data Object
| Parameter | Type | Description |
|---|---|---|
| booking_id | string | Booking ID for the on-demand shipment |
| ondemand_service_id | string | ID of the selected on-demand service |
| order_number | string | Unique order number |
| tracking_url | string | URL to track the delivery |
| courier | object | Courier service information |
| pricing_breakdown | object | Price breakdown of the order |
| shipment | object | Submitted shipment details |
Courier Object
| Parameter | Type | Description |
|---|---|---|
| service_id | int | Courier's service ID |
| courier_name | string | Name of the courier |
| img_courier | string | Logo URL of the courier |
Pricing Breakdown
| Parameter | Type | Description |
|---|---|---|
| currency_code | string | Currency used (e.g., MYR) |
| total_order_amount | string | Final amount before any coupon |
| total_paid_amount | string | Amount paid after coupon applied |
| shipment_amount | string | Delivery cost without tax |
| tax_amount | string | Tax applied to the shipment |
| coupon_redeemed | string | Amount discounted using the coupon |
Shipment Object
| Parameter | Type | Description |
|---|---|---|
| coupon_codes | array | Applied coupon codes (if any) |
| origin_country | string | Country code of the shipment origin |
| ondemand_service_id | string | Service ID used |
| schedule_pickup_date | string | Scheduled pickup date |
| schedule_pickup_time | string | Scheduled pickup time |
| time_zone | string | Time zone of the schedule |
| metadata | object | Additional metadata (e.g., quotationId) |
| waypoint | array | Pickup and dropoff location details |
Waypoint Object
| Parameter | Type | Description |
|---|---|---|
| point | int | Sequence point (0=pickup, 1=dropoff) |
| type | string | Type of point ('pickup'/'dropoff') |
| remark | string | Remark or notes for the waypoint |
| coordinates | object | Latitude and longitude |
| item | array | Items associated with this stop |
| shipment_info | object | Sender or receiver contact details |
Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (Requests)
fetch("https://api.easyparcel.com/ondemand/order", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
},
body: JSON.stringify({ ... })
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$ch = curl_init("https://api.easyparcel.com/ondemand/order");
$data = [ ... ];
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = "https://api.easyparcel.com/ondemand/order"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
data = { ... }
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for OnDemand Submit Order
- Validate your data before sending the request, especially coordinates and item dimensions.
- Use quotationId from the Get Quotation API in
metadatato ensure pricing consistency. - Respect rate limits by not firing too many requests in a short time.
- Ensure date and time format follow
YYYY-MM-DDandHH:MM:SSstandards. - Always include proper contact details to avoid delivery failure.
- Secure your access token and never expose it in public repositories.
- Use sandbox/test environment for testing before going live.
OnDemand Coupon
The coupon feature allows customers to search for available promo codes and apply them during the shipment order submission. This helps users enjoy discounted rates or special benefits based on current promotional campaigns.
HTTP Request (OnDemand Coupon List)
Customers can retrieve a list of available coupon codes using the following endpoint:
GET https://api.easyparcel.com/open_api/2025-06/ondemand/get_coupon_list
This will return a list of valid promo codes available to use for the shipment from the user’s account, based on factors such as delivery type, courier, or region.
OnDemand Coupon Request
Submitting to the Coupon Listing Endpoint based on the submit shipment order endpoint request to get the available coupon for the shipment
Sample Coupon Listing Request:
{
"origin_country": "MY",
"ondemand_service_id": "EP-CS0F",
"schedule_pickup_date": "2024-11-30",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3419574389920977479"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "1278491622",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Assis",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oren",
"email": "oren@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
OnDemand Coupon Response
Sample Respone for the coupon listing
{
"status_code": 200,
"message": "4 coupon(s) available",
"data": {
"account_id": 438368,
"currency_code": "MYR",
"coupons": [
{
"coupon_code": "77f39c22-427a-44f1-8bff-e4f3752ba165",
"title": "Test Coupon 1",
"description": "Test ",
"discounted_amount": "5.01",
"discount_rate": "20.00%",
"valid_from_date": "2025-05-12 18:04:33",
"valid_to_date": "2025-09-14 18:04:33"
},
{
"coupon_code": "10101f8b-1dc5-49e0-b4d3-09c5deb76513",
"title": "Test Coupon",
"description": "vvffg",
"discounted_amount": "2.34",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "dfa5109a-2f35-427e-8482-9b0ab65c323f",
"title": "Test Coupon",
"description": "vvffg",
"discounted_amount": "2.10",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
},
{
"coupon_code": "ad205174-d93d-4d6a-a5cc-1e989b0292eb",
"title": "Test Coupon",
"description": "vvffg",
"discounted_amount": "1.89",
"discount_rate": "10.00%",
"valid_from_date": "2025-05-12 09:43:43",
"valid_to_date": "2025-07-13 09:43:43"
}
]
}
}
Coupon Listing API - Response Parameters
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code indicating success or failure |
| message | string | Description of the response message |
| data | object | Container for coupon and account details |
data Object
| Parameter | Type | Description |
|---|---|---|
| account_id | int | The EasyParcel account ID |
| currency_code | string | Currency in which the discount is offered (e.g., MYR) |
| coupons | array | List of coupon objects available for use |
coupon Object (Inside coupons array)
| Parameter | Type | Description |
|---|---|---|
| coupon_code | string | Unique identifier for the coupon |
| title | string | Title or name of the coupon campaign |
| description | string | Description or note about the coupon |
| discounted_amount | string | Discount value in currency terms |
| discount_rate | string | Discount in percentage (e.g., "10.00%") |
| valid_from_date | string | Start datetime of coupon validity (UTC format) |
| valid_to_date | string | End datetime of coupon validity (UTC format) |
Applying Coupons
During the order submission process (e.g., /shipment/submit or /ondemand/shipment/submit), customers can apply a valid coupon code by including it in the request body.
To apply coupon just adding the coupon_codes parameters to the request
Sample Field in Submit Orders:
{
"coupon_codes":["dfa5109a-2f35-427e-8482-9b0ab65c323f"],
"origin_country": "MY",
"ondemand_service_id": "EP-CS0F",
"schedule_pickup_date": "2024-11-30",
"schedule_pickup_time": "11:48:35",
"time_zone": "Asia/Kuala_Lumpur",
"metadata": {
"quotationId": "3419574389920977479"
},
"waypoint": [
{
"point": 0,
"type": "pickup",
"remark": "1",
"coordinates": {
"latitude": 5.342720241204454,
"longitude": 100.28204988381822
},
"item": [
{
"quantity": "1",
"description": "1",
"dimensions": {
"height": "1",
"width": "1",
"length": "1",
"weight": "1"
}
}
],
"shipment_info": {
"phone_number_country_code": "MY",
"phone_number": "1278491622",
"address": "Kawasan Mendaki Bukit Jambul, Lintang Bukit Jambul 1, Bukit Jambul Indah, Bayan Lepas, Mukim 13 Paya Terubong, 11900, Timur Laut, Pulau Pinang, Malaysia",
"name": "Assis",
"email": "as@gmail.com"
}
},
{
"point": 1,
"type": "dropoff",
"remark": "2",
"coordinates": {
"latitude": 5.325513957,
"longitude": 100.2862732
},
"item": [
{
"quantity": "2",
"description": "2",
"dimensions": {
"height": "2",
"width": "2",
"length": "2",
"weight": "2"
}
}
],
"shipment_info": {
"name": "Oren",
"email": "oren@gmail.com",
"phone_number_country_code": "MY",
"phone_number": "127491622",
"address": "Suntech @ Penang Cybercity, 1, Lintang Mayang Pasir 3, Bandar Bayan Baru, Bayan Lepas, Mukim 12 Bayan Lepas, 11950, Barat Daya, Pulau Pinang, Malaysia"
}
}
]
}
If the coupon is valid and applicable, the discounted amount will be reflected in the final pricing.
Please ensure the coupon is valid and not expired before applying. For additional validation feedback, refer to the response message from the submission endpoint.
OnDemand Order Cancellation
This guide explains how to cancel an on-demand shipment order.
Endpoint URL
POST https://api.easyparcel.com/2025-06/ondemand/cancel
OnDemand Cancel Request
| Parameter | Type | Required | Description |
|---|---|---|---|
| booking_id | string | yes | booking number/id of the ondemand shipment |
-
Request Example
{
"booking_id": "EOD-156"
}
OnDemand Cancel Response
Sample Response
{
"status_code": 200,
"message": "success",
"data": [
{
"message": "Shipment cancelled successfully",
"booking_id": "EOD-156"
}
]
}
Main Response
| Parameter | Type | Description |
|---|---|---|
| status_code | int | HTTP status code (e.g., 200) |
| message | string | Success or error message |
| data | object | Contains booking details and shipment info |
Cancellation
| Parameter | Type | Description |
|---|---|---|
| message | string | message for the cancelled status |
| booking_id | string | booking id/number of the ondemand status |
Code Implementation Examples
JavaScript (Fetch API) | PHP (cURL) | Python (Requests)
fetch("https://api.easyparcel.com/ondemand/cancel", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
},
body: JSON.stringify({
booking_id: "EOD-156"
})
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$ch = curl_init("https://api.easyparcel.com/ondemand/cancel");
$data = [
"booking_id" => "EOD-156"
];
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer YOUR_ACCESS_TOKEN'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
import requests
url = "https://api.easyparcel.com/ondemand/cancel"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
data = {
"booking_id": "EOD-156"
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
Best Practices for OnDemand Cancel Order
- Always include a valid
booking_idwhen attempting to cancel an order. - Ensure the order is eligible for cancellation (i.e., not already picked up or completed).
- Handle the response gracefully, including possible failure messages.
- Use test credentials in sandbox mode for testing integration before going live.
- Rate limit your API calls to avoid service throttling or rejection.
- Log your cancellation attempts for traceability and support reference.
- Secure your access token and never expose it in public repositories or front-end code.
Account Related Endpoints
Account related will provides features related to your easyparcel account such as receiving account details.
Wallet Balance
This endpoint allows users to retrieve their current wallet balance and free credit information.
HTTP Request (Wallet)
GET https://api.easyparcel.com/open_api/2025-06/wallet
Request Wallet Parameters
This endpoint does not require any request parameters. Authentication is handled through Oauth 2.0 access token.
Request Sample for Wallet
No request body required
Response Wallet Parameters
Response Sample for Wallet
{
"status_code": 200,
"message": "Success",
"data": {
"wallet": [
{
"balance": 9999999123.88,
"currency": "MYR"
}
],
"free_credit_wallet": [
{
"balance": 0,
"currency": "MYR"
}
]
}
}
Main Response Structure
| Parameter | Type | Description |
|---|---|---|
| status_code | int | Status code of the response |
| message | string | Response message |
| data | object | Contains wallet information |
Data Object
| Parameter | Type | Description |
|---|---|---|
| wallet | array | Array of wallet balances |
| free_credit_wallet | array | Array of free credit balances |
Wallet Object
| Parameter | Type | Description |
|---|---|---|
| balance | double | Available balance in the wallet |
| currency | string | Currency code of the balance |
Free Credit Wallet Object
| Parameter | Type | Description |
|---|---|---|
| balance | double | Available free credits |
| currency | string | Currency code of the free credits |
Error Response for Wallet
If there's an authentication issue or server error, the API will return an error response:
{
"status_code": 401,
"message": "Unauthorized access",
"data": null
}
Usage Notes for Wallet
- This endpoint provides the current balance in your EasyParcel wallet, which can be used for shipping services.
- The response includes both regular wallet balance and free credit balance.
- Free credits may have expiration dates and usage restrictions that are not included in this response.
- Multiple currency wallets are supported, though most accounts will only have one currency.
- The balance is updated in real-time and reflects the current available amount for shipping services.
- Wallet balances can be topped up through the EasyParcel dashboard or using the top-up API endpoints (if available).
- Always ensure your account has sufficient balance before submitting shipment orders to avoid processing delays.
Webhooks
How to Subscribe to Webhooks
Prerequisites
Before setting up webhooks, ensure you have: - An active EasyParcel developer account - A configured app in the Developer Hub - A valid endpoint URL that can receive POST requests - Your endpoint configured to handle webhook payloads
Subscription Steps
Follow these steps to subscribe to webhooks:
1. 🎯 Navigate to App Settings
- Go to Developer Hub Dashboard
- Click on Apps
- Select Settings on the app you wish to configure webhooks for
2. 📡 Access Webhook Configuration
- In the left sidebar, click Webhook
- Click the Add Endpoint button
3. ⚙️ Configure Webhook Details
- Enter Endpoint URL: Input the URL that will receive the webhook payload
- Select Webhook Topic: Choose the event(s) you want to subscribe to from the available options
- Verify Configuration: Double-check your URL and selected topics
4. 💾 Save Configuration
- Press Save to confirm your webhook settings
- Your webhook endpoint will be validated
5. ✅ Confirmation
- Done! Your webhook is now active and will be triggered according to your selected topics
- Test your endpoint to ensure it's receiving webhook data correctly
Webhook Topics
| Topic ID | Webhook Topic Name | Description |
|---|---|---|
| 1 | Ondemand Order Status Update | Triggered when an on-demand order status changes |
| 2 | Shipment Status Update | Triggered when a shipment status changes |
| 3 | Shipment AWB Update | Triggered when a shipment AWB (Air Waybill) is updated |
| 4 | Tracking Status Update | Triggered when package tracking status is updated |
| 5 | Shipment Created | Triggered when a new shipment is created |
Webhook Sample Payload:
//Shipment Status Update Sample:
{
"topic": "shipment.awb.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "238725129086",
"awb_url":"http:\/\/demo.connect.easyparcel.my\/?ac=AWBLabel&id=QmIxTE43eHQjMTYzMDQwMTI%3D",
"tracking_url":"https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001523"
}
//Shipment AWB Update Sample:
{
"topic": "shipment.awb.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "23872512999",
"awb_url":"http:\/\/demo.connect.easyparcel.my\/?ac=AWBLabel&id=QmIxTE43eHQjMTYzMDQwAAA%3D",
"tracking_url":"https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001999"
}
//Shipment AWB Update Sample:
{
"topic": "shipment.tracking.update",
"shipment_number": "ES-2504-G7FDF",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"awb_number": "238725129086",
"latest_shipment_status_code":5,
"latest_tracking_status": "Deliverd To Suntech",
"timestamp":"2017-10-28 11:40:00",
"status_log":[
"0":{
"timestamp":"2017-10-28 11:40:00",
"shipment_status_code":5,
"tracking_status" : "Deliverd To Suntech"
},
"1":{
"timestamp":"2017-06-28 12:00:00",
"shipment_status_code":3,
"tracking_status":"Parcel has been collected at Penang"
}
]
}
//Shipment Create Sample:
{
"shipment_number": "WEBHOOK-TEST-001",
"uuid": "webhook-test-uuid-123",
"timestamp":"2017-10-28 11:40:00",
"sender_name": "Test Sender",
"receiver_name": "Test Receiver",
"sender_phone_number": "0123456789",
"receiver_phone_number": "0987654321",
"sender_email": "sender@test.com",
"receiver_email": "receiver@test.com",
"sender_address1": "Test Address 1",
"receiver_address1": "Test Address 1",
"sender_postcode": "12345",
"receiver_postcode": "54321",
"sender_city": "Test City",
"receiver_city": "Test City",
"sender_country_code": "MY",
"receiver_country_code": "MY",
"weight": 1.0,
"length": 10,
"width": 10,
"height": 10,
"service_id": 1,
"courier_id": 1,
"status": 1
}
//Ondemand Order Status Update Sample:
{
"topic": "ondemand.status.update",
"order_number": "EODWEBHOOK-TEST-001",
"tracking_url": "https:\/\/easyparcel.com\/my\/en\/track\/details\/?courier=Skynet&awb=23877001523",
"status": 0,
"timeline": ,
"driver": {
"id": "81994", "name": "TestDriver 09090", "phone": "+6090909090", "photo": "", "rating": "", "vehicle": {"model": "", "licensePlate": "VP5734736", "physicalVehicleType": "Bike"}, "coordinates": {"latitude": 0, "longitudelatitude": 0 }
},
"event_date": "2025-06-06 04:21:07",
"waypoint": [
{"pod": null, "coordinate": {"latitude": 5.325513957, "longitude": 100.2862732}},
{"pod": "http://sg-oimg-pre.lalamove.com/appdriver/pre/appdriver/2021/07/05/1625479646347738192598.png", "coordinate": {"latitude": 5.325513957, "longitude": 100.2862732}}
],
}
Usage Notes for Webhooks
- Multiple Subscriptions: You can subscribe to multiple topics for the same endpoint
- Event Filtering: Choose only the topics relevant to your application to reduce unnecessary webhook calls
Important Notes for Webhooks
- Endpoint Requirements: Your URL must be publicly accessible and able to handle POST requests
- Multiple Topics: You can subscribe to multiple webhook topics for the same endpoint
- Payload Format: All webhooks send JSON payloads with event-specific data
- Response Expected: Your endpoint should return a 200 status code to acknowledge receipt
- Retry Logic: Failed webhook deliveries may be retried automatically
Testing Your Webhook
After setup, verify your webhook is working: 1. Trigger a test event in your app 2. Check your endpoint logs for incoming requests 3. Verify the payload structure matches your expectations 4. Ensure your endpoint responds with HTTP 200
🛠️ Troubleshooting for Webhooks
Common Issues: - Endpoint not receiving data: Verify URL is publicly accessible - SSL/HTTPS required: Ensure your endpoint uses HTTPS - Timeout errors: Your endpoint should respond quickly (within 30 seconds) - Invalid responses: Return proper HTTP status codes
References
ISO 3166
At EasyParcel, we adhere to the ISO 3166 standard for the identification of states, provinces, and zones. For example, the code "MY-07" corresponds to the state of Penang in Malaysia.
ISO 3166 is a standard published by the International Organization for Standardization (ISO) that defines codes for the names of countries, dependent territories, special areas of geographical interest, and their principal subdivisions (e.g., provinces or states). The official name of the standard is Codes for the representation of names of countries and their subdivisions. make this sentences better
Country Code
| Short Country Name | Full Country Name |
|---|---|
| SR | SURINAME |
| SD | SUDAN |
| VC | ST. VINCENT |
| XM | ST. MAARTEN |
| LC | ST. LUCIA |
| KN | ST. KITTS |
| XE | ST. EUSTATIUS |
| BL | ST. BARTHELEMY |
| LK | SRI LANKA |
| ES | SPAIN |
| ZA | SOUTH AFRICA |
| XS | SOMALILAND (NORTH SOMALIA) |
| SO | SOMALIA |
| SB | SOLOMON ISLANDS |
| SI | SLOVENIA |
| SK | SLOVAKIA |
| SG | SINGAPORE |
| SL | SIERRA LEONE |
| SC | SEYCHELLES |
| RS | SERBIA |
| SN | SENEGAL |
| SA | SAUDI ARABIA |
| ST | SAO TOME AND PRINCIPE |
| SM | SAN MARINO |
| WS | SAMOA |
| MP | SAIPAN |
| RW | RWANDA |
| RU | RUSSIAN FEDERATION |
| RO | ROMANIA |
| RE | REUNION |
| QA | QATAR |
| PR | PUERTO RICO |
| PT | PORTUGAL |
| PL | POLAND |
| PH | PHILIPPINES |
| PE | PERU |
| PY | PARAGUAY |
| PG | PAPUA NEW GUINEA |
| PA | PANAMA |
| PW | PALAU |
| PK | PAKISTAN |
| OM | OMAN |
| NO | NORWAY |
| NU | NIUE |
| NG | NIGERIA |
| NE | NIGER |
| NI | NICARAGUA |
| NZ | NEW ZEALAND |
| NC | NEW CALEDONIA |
| XN | NEVIS |
| NL | NETHERLANDS |
| NP | NEPAL |
| NR | NAURU |
| NA | NAMIBIA |
| MM | MYANMAR |
| MA | MOROCCO |
| MS | MONTSERRAT |
| ME | MONTENEGRO |
| MN | MONGOLIA |
| MC | MONACO |
| MD | MOLDOVA, REPUBLIC OF |
| FM | MICRONESIA, FEDERATED STATES OF |
| MX | MEXICO |
| YT | MAYOTTE |
| MU | MAURITIUS |
| MR | MAURITANIA |
| MQ | MARTINIQUE |
| MH | MARSHALL ISLANDS |
| MT | MALTA |
| ML | MALI |
| MV | MALDIVES |
| MW | MALAWI |
| MY | MALAYSIA |
| MG | MADAGASCAR |
| MK | MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF |
| MO | MACAU |
| LU | LUXEMBOURG |
| LT | LITHUANIA |
| LI | LIECHTENSTEIN |
| LY | LIBYA |
| LR | LIBERIA |
| LS | LESOTHO |
| LB | LEBANON |
| LV | LATVIA |
| LA | LAO PEOPLE'S DEMOCRATIC REPUBLIC |
| KG | KYRGYZSTAN |
| KW | KUWAIT |
| XK | KOSOVO |
| KR | KOREA, REPUBLIC OF |
| KP | KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF |
| KI | KIRIBATI |
| KE | KENYA |
| KZ | KAZAKHSTAN |
| JO | JORDAN |
| JE | JERSEY |
| JP | JAPAN |
| JM | JAMAICA |
| IT | ITALY |
| IL | ISRAEL |
| IE | IRELAND |
| IQ | IRAQ |
| IR | IRAN, ISLAMIC REPUBLIC OF |
| ID | INDONESIA |
| IN | INDIA |
| IS | ICELAND |
| HU | HUNGARY |
| HK | HONG KONG |
| HN | HONDURAS |
| HT | HAITI |
| GY | GUYANA |
| GW | GUINEA BISSAU |
| GN | GUINEA REPUBLIC |
| GG | GUERNSEY |
| GT | GUATEMALA |
| GU | GUAM |
| GP | GUADELOUPE |
| GD | GRENADA |
| GL | GREENLAND |
| GR | GREECE |
| GI | GIBRALTAR |
| GH | GHANA |
| DE | GERMANY |
| GE | GEORGIA |
| GM | GAMBIA |
| GA | GABON |
| ZW | ZIMBABWE |
| FR | FRANCE |
| FI | FINLAND |
| ZM | ZAMBIA |
| FJ | FIJI |
| YE | YEMEN |
| FO | FAROE ISLANDS |
| FK | FALKLAND ISLANDS (MALVINAS) |
| ET | ETHIOPIA |
| VI | VIRGIN ISLANDS, U.S. |
| EE | ESTONIA |
| VG | VIRGIN ISLANDS, BRITISH |
| ER | ERITREA |
| GQ | EQUATORIAL GUINEA |
| SV | EL SALVADOR |
| EG | EGYPT |
| VN | VIETNAM |
| EC | ECUADOR |
| TP | EAST TIMOR |
| VE | VENEZUELA |
| DO | DOMINICAN REPUBLIC |
| DM | DOMINICA |
| DJ | DJIBOUTI |
| VU | VANUATU |
| DK | DENMARK |
| CZ | CZECH REPUBLIC |
| CY | CYPRUS |
| CU | CUBA |
| UZ | UZBEKISTAN |
| UY | URUGUAY |
| HR | CROATIA |
| CI | COTE D'IVOIRE |
| CR | COSTA RICA |
| CK | COOK ISLANDS |
| CD | CONGO, THE DEMOCRATIC REPUBLIC OF THE |
| UM | UNITED STATES MINOR OUTLYING ISLANDS |
| CG | CONGO |
| KM | COMOROS |
| CN | CHINA |
| US | UNITED STATES |
| GF | FRENCH GUIANA |
| AN | NETHERLANDS ANTILLES |
| MZ | MOZAMBIQUE |
| CW | CURACAO |
| CO | COLOMBIA |
| CL | CHILE |
| TD | CHAD |
| CF | CENTRAL AFRICAN REPUBLIC |
| KY | CAYMAN ISLANDS |
| GB | UNITED KINGDOM |
| CV | CAPE VERDE |
| AE | UNITED ARAB EMIRATES |
| IC | CANARY ISLANDS, THE |
| CA | CANADA |
| UA | UKRAINE |
| CM | CAMEROON |
| KH | CAMBODIA |
| UG | UGANDA |
| BI | BURUNDI |
| BF | BURKINA FASO |
| BG | BULGARIA |
| BN | BRUNEI DARUSSALAM |
| TV | TUVALU |
| BR | BRAZIL |
| TC | TURKS AND CAICOS ISLANDS |
Add-On Feature: EasyParcel Tracking Notification
Real-time parcel tracking has become essential in today’s fast-paced logistics environment. To improve user experience and enhance transparency, EasyParcel offers multiple tracking notification methods as add-on features for on-demand and standard delivery services.
📲 Tracking SMS
Tracking SMS allows recipients to receive real-time parcel status updates via SMS. Notifications are automatically sent when the parcel is dispatched, in transit, or out for delivery. This is especially helpful for users who are always on the go and prefer quick updates without logging into the platform.
📧 Tracking Email
With Tracking Email, recipients receive status updates directly in their inboxes. This is an ideal solution for users who rely heavily on email and want to maintain a full history of parcel status in one place. Updates are triggered automatically as the parcel progresses through various delivery stages.
💬 Tracking WhatsApp
WhatsApp Tracking is a modern, interactive way to stay informed about parcel movements. Notifications are delivered straight to the recipient’s WhatsApp chat, making it easy to follow updates in real-time and share parcel progress with others if needed.
These tracking features are available for EasyParcel users across various supported countries. Please refer to your local EasyParcel platform for feature availability and pricing. You may also run the Get Shipment Quotation endpoint to retrieve pricing details for available tracking features. These tracking features can be activated through the Submit Order endpoint during order creation.
EasyParcel Coupon Feature
EasyParcel’s coupon feature offers customers a convenient way to enjoy special discounts, seasonal promotions, and loyalty rewards. These promo codes help users save on shipping costs and encourage engagement through exclusive campaign offers.
🎁 What Are EasyParcel Coupons?
Coupons are promo codes issued by EasyParcel that provide instant rebates or special perks when applied to a shipment. They can be targeted based on delivery types, couriers, regions, or customer eligibility (e.g., new users, festive deals).
🔍 Where to Find Coupons
Customers can browse available coupons directly through the EasyParcel platform. These offers may appear on promotional banners, in user dashboards, or be provided via campaigns. Developers can also retrieve available coupons programmatically using the designated API endpoint.
🧾 How to Use Coupons
To enjoy a discount, users simply need to enter the valid coupon code during order submission. If the coupon meets the required conditions, the discount will be reflected in the final price.
Please note that coupon availability and eligibility may vary by country, courier, and shipping method. Always check the terms associated with each coupon before use.
Cancel Order
This section introduces the cancellation features available for both standard and ondemand shipments on the EasyParcel platform.
❗ Important Cancellation Conditions
- 7-Day Limit: Cancellation requests must be submitted within 7 days from the scheduled collection date.
- No Cancellation After Pickup: Once the courier driver has picked up the parcel, cancellation is no longer permitted.
- Refunds: If the cancellation is successful, the shipment cost will be refunded to the user's credit wallet.
📡 Relevant Endpoints
Bulk Cancellation Support:
- Standard shipments support bulk cancellation.
- Ondemand shipments must be cancelled individually.
/shipment/cancel– for standard shipment cancellations./ondemand/shipment/cancel– for ondemand shipment cancellations.
EasyParcel API Standards
This document outlines the standard formats for requests and responses when working with the EasyParcel API.
Request Format Standards
General Guidelines
- All requests must be sent as HTTP POST requests
- Content-Type header should be set to
application/json - Authentication is handled via Oauth 2.0 access token in the headers
- All request payloads should be valid JSON objects
- DateTime values should use the format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS
Common Request Structure
Most EasyParcel API endpoints follow a consistent request format:
Single Resource Requests - Simple requests with a single parameter set:
json { "parameter1": "value1", "parameter2": "value2" }Batch Requests - Requests involving multiple items follow an array pattern:
json { "resource_name": [ { /* item 1 details */ }, { /* item 2 details */ } ] }
Example Request Types
Shipment Submission
Batch format with shipment array containing multiple shipment objects:
{
"shipment": [
{
"service_id": "EP-CS09Q",
"collection_date": "2025-05-02",
"weight": 2.5,
"height": 30,
"length": 40,
"width": 20,
"item": [ /* items array */ ],
"sender": { /* sender details */ },
"receiver": { /* receiver details */ },
"feature": { /* feature settings */ }
},
// Additional shipments...
]
}
Quotation Request
Similar batch format with shipment array containing multiple quote requests:
{
"shipment": [
{
"sender": {
"postcode": "10150",
"subdivision_code": "MY-02",
"country": "MY"
},
"receiver": {
"postcode": "018916",
"subdivision_code": "SG-04",
"country": "SG"
},
"parcel_value": 50,
"weight": 0.5,
"width": 5,
"length": 5,
"height": 5
},
// Additional quote requests...
]
}
Shipment Listing Request
Simple parameter format for filtering and pagination:
{
"limit": 3,
"before_shipment_number": "ES-2504-B944M",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Response Format Standards
General Guidelines
- All responses are returned as JSON objects
- Every response includes
status_code,message, anddatafields - Successful operations return status code 200
- Error details are provided in both the message and data sections
- Batch operations provide individual success/failure information for each item
Common Response Structure
{
"status_code": 200,
"message": "success",
"data": [
/* Response data objects */
]
}
Success Response Patterns
Single Resource Response
{
"status_code": 200,
"message": "success",
"data": {
"resource_property1": "value1",
"resource_property2": "value2"
}
}
Batch Operation Response
{
"status_code": 200,
"message": "2 requests success, 1 request error.",
"data": [
{
"status": "success",
"message": "Order Processed",
"item_id": "12345"
},
{
"status": "success",
"message": "Order Processed",
"item_id": "12346"
},
{
"status": "error",
"message": "Invalid postal code",
"item_id": "12347"
}
]
}
Collection Response
{
"status_code": 200,
"message": "success",
"data": [
{ /* Item 1 */ },
{ /* Item 2 */ },
{ /* Item 3 */ }
]
}
Error Response Patterns
Request Validation Error
{
"status_code": 400,
"message": "Validation failed",
"data": {
"errors": [
"The service_id field is required",
"The collection_date field is required"
]
}
}
Resource Not Found
{
"status_code": 404,
"message": "No Order with shipment_number ES-2504-3WYYP found from this account",
"data": []
}
Authentication Error
{
"status_code": 401,
"message": "Invalid Oauth 2.0 access token",
"data": null
}
Partial Success in Batch Operations
{
"status_code": 200,
"message": "1 requests success, 2 request error.",
"data": [
{
"status": "success",
"message": "Order Cancelled",
"shipment_number": "ES-2504-WZ9VY"
},
{
"status": "error",
"message": "Shipment Already Cancelled",
"shipment_number": "ES-2504-JUB4T"
},
{
"status": "error",
"message": "Shipment Not Found",
"shipment_number": "ES-2504-INVALID"
}
]
}
Common Field Types
| Field Type | Format | Example |
|---|---|---|
| Date | YYYY-MM-DD | 2025-05-02 |
| DateTime | YYYY-MM-DD HH:MM:SS | 2025-05-02 14:30:00 |
| Weight | Numeric (kg) | 2.5 |
| Dimensions | Numeric (cm) | 30 |
| Currency | ISO Currency Code | MYR |
| Country Code | ISO Country Code | MY |
| Subdivision Code | ISO 3166-2 code | MY-07 |
| Phone Code | With "+" prefix | +60 |
| Boolean | true/false | true |
Best Practices
- Validate Input: Always validate request parameters against the API documentation before submission
- Check Status Codes: Always check the status_code in the response
- Handle Batch Responses: For batch operations, check individual status values for each item
- Error Handling: Implement proper error handling based on the error message patterns
- Pagination: For list endpoints, use the provided pagination mechanisms with
limitandbefore_shipment_number - Date Ranges: When using date ranges, ensure
date_fromis earlier thandate_to - Field Lengths: Respect the maximum field lengths specified in the API documentation
Notes on API Versioning
The API version is included in the URL path: /open_api/2025-06/
Always use the appropriate version for your implementation to ensure compatibility.
EasyParcel API Error Handling Guide
This document outlines the common error patterns and recommended handling strategies when working with the EasyParcel API.
Error Response Patterns
The EasyParcel API returns specific error formats depending on the type of error encountered. Understanding these patterns will help you implement proper error handling in your integration.
Authentication Errors
When authentication fails, you'll receive a response in this format:
{
"error": {
"statusCode": 401,
"status": 401,
"code": 401,
"name": "invalid_token"
},
"status_code": 401
}
Common Authentication Error Codes
| Error Name | Description | Recommended Action |
|---|---|---|
| invalid_token | The Oauth 2.0 access token is invalid or expired | Verify your Oauth 2.0 access token and request a new one if needed |
| missing_token | No Oauth 2.0 access token was provided in the request | Ensure Oauth 2.0 access token is included in the request header |
| insufficient_scope | The Oauth 2.0 access token doesn't have permission for this action | Request appropriate permissions for your Oauth 2.0 access token |
Validation Errors
Single Resource Validation
For single resource operations with validation errors:
{
"status_code": 400,
"message": "Validation error",
"data": {
"errors": [
"The service id field is required",
"The collection date field is required"
]
}
}
Batch Operation Errors
For batch operations, the API may return a mix of successful and failed operations:
Complete Batch Failure
{
"status_code": 200,
"message": "0 requests success, 3 request error.",
"data": [
{
"order_details": {
"account_id": "438671"
},
"pricing": {
"currency_code": "MYR",
"total_amount": "0.00",
"total_tax_amount": "0.00"
},
"shipments": [
{
"status": "error",
/* shipment details */
"errors": [
"The service id field is required",
"The collection date field is required",
"The receiver phone number country code field is required",
"The receiver phone number field is required",
"The receiver address 1 field is required"
]
},
/* additional failed shipments */
]
}
]
}
Partial Success in Batch Operations
{
"status_code": 200,
"message": "1 request success, 1 request error.",
"data": [
{
"order_details": {
"order_number": "EI-2504-6WFXC",
"account_id": 438671
},
"pricing": {
"currency_code": "MYR",
"total_amount": "27.83",
"total_tax_amount": "1.63"
},
"shipments": [
{
"status": "success",
/* successful shipment details */
},
{
"status": "error",
/* failed shipment details */
"errors": [
"The service id field is required",
"The collection date field is required"
]
}
]
}
]
}
Quotation Errors
Quotation endpoints also follow the batch processing pattern, where some items may succeed while others fail:
{
"status_code": 200,
"message": "1 request success, 2 request error.",
"data": [
{
"status": "success",
"input": { /* input details */ },
"quotations": [ /* quotation results */ ]
},
{
"status": "error",
"input": { /* input details */ },
"errors": [
"The receiver postcode is invalid"
]
},
{
"status": "error",
"input": { /* input details */ },
"errors": [
"The receiver country field is required"
]
}
]
}
Common Error Messages
Here are some common error messages you may encounter and how to resolve them:
Request Validation Errors
| Error Message | Possible Cause | Resolution |
|---|---|---|
| "The service id field is required" | Missing service_id in request | Include a valid service_id from courier list |
| "The collection date field is required" | Missing or invalid collection_date | Provide a valid date in YYYY-MM-DD format |
| "The receiver phone number field is required" | Missing receiver phone number | Include the receiver's phone number |
| "The receiver address 1 field is required" | Missing primary address line | Include the first line of the receiver's address |
| "The receiver postcode is invalid" | Invalid or non-existent postal code | Verify the postal code with the courier service |
| "The receiver country field is required" | Missing country code | Include a valid country code (e.g., "MY" for Malaysia) |
Business Logic Errors
| Error Message | Possible Cause | Resolution |
|---|---|---|
| "Shipment Already Cancelled" | Attempting to cancel an already cancelled shipment | Check shipment status before cancellation request |
| "No Order with shipment_number X found" | Incorrect shipment number or not owned by account | Verify the shipment number belongs to your account |
| "Shipment Cannot Be Cancelled" | Shipment is in a state that can't be cancelled | Only shipments in certain states can be cancelled |
| "Weight exceeds service limits" | Parcel exceeds courier weight restrictions | Choose a different service or reduce parcel weight |
| "Service not available for origin/destination" | Route not serviced by selected courier | Choose a different courier service |
Error Handling Best Practices
1. Check Status Code and Message
Always check both the status_code and message fields to properly identify errors. A 200 status code does not always mean complete success in batch operations.
2. Handle Batch Operations Carefully
For batch operations:
- Parse the message field to determine success/error counts
- Iterate through each item in the data array
- Check the status field of each item
- Process successful items and handle errors for failed items
3. Implement Retry Logic
For transient errors (e.g., network issues, temporary service unavailability), implement a retry mechanism with exponential backoff.
4. Log Detailed Error Information
Log detailed error information for troubleshooting, including: - Request parameters - Complete error response - Timestamp - API endpoint
5. Handle Validation Errors Proactively
Implement client-side validation based on known API requirements to reduce validation errors.
6. Check for Partial Success
Always assume batch operations may partially succeed and handle accordingly:
// Example handling of a batch response
function handleBatchResponse(response) {
console.log(`Processing response: ${response.message}`);
if (response.status_code !== 200) {
return handleNonSuccessStatusCode(response);
}
// Extract success/failure counts from message
const messageParts = response.message.split(',');
const successCount = parseInt(messageParts[0].match(/\d+/)[0]);
const errorCount = parseInt(messageParts[1].match(/\d+/)[0]);
console.log(`Shipments: ${successCount} successful, ${errorCount} failed`);
// Process data
response.data.forEach(order => {
if (order.shipments) {
order.shipments.forEach(shipment => {
if (shipment.status === 'success') {
processSuccessfulShipment(shipment);
} else {
handleFailedShipment(shipment);
}
});
}
});
}
Authentication Error Recovery
If you encounter authentication errors:
- Verify your Oauth 2.0 access token is correct
- Check if your Oauth 2.0 access token has expired
- Request a new Oauth 2.0 access token if necessary
- Ensure your system securely stores the Oauth 2.0 access token
- Implement automatic token refresh if supported
Common HTTP Status Codes
| Status Code | Description | Handling Strategy |
|---|---|---|
| 200 | Success (may include errors) | Check message and individual item status |
| 400 | Bad Request | Fix request parameters based on error details |
| 401 | Unauthorized | Refresh or update API credentials |
| 403 | Forbidden | Request appropriate permissions |
| 404 | Not Found | Verify resource identifiers |
| 429 | Too Many Requests | Implement rate limiting and backoff strategy |
| 500 | Server Error | Retry with exponential backoff |
Troubleshooting Guide
Oauth 2.0 access token Issues
- Ensure Oauth 2.0 access token is not expired
- Verify Oauth 2.0 access token is correctly included in the authorization header
- Check if your account has the necessary permissions
Invalid Input
- Validate all required fields are present
- Ensure postal codes are valid for the respective countries
- Verify dimensions and weights are within courier limitations
Service Availability
- Check if selected service is available for the specific route
- Verify the courier is operational on the requested collection date
- Confirm service availability for international routes
Shipment Status Issues
- Verify shipment status before attempting to modify or cancel
- Check if the shipment number exists and belongs to your account
- Ensure operations are performed within allowed timeframes (e.g., cancellation window)
Contact Support
If you encounter persistent errors that cannot be resolved through this guide, contact EasyParcel support with the following information:
- Complete request and response details
- Timestamp of the request
- API endpoint used
- Description of the expected vs. actual behavior
- Steps taken to troubleshoot the issue
Pagination Guide for EasyParcel API
This document outlines the pagination mechanism used in the EasyParcel API for endpoints that return multiple records, such as shipment listings and on-demand service listings.
Pagination Overview
EasyParcel API uses cursor-based pagination for list endpoints. This method is more efficient than traditional page number-based pagination, especially for large datasets.
How Pagination Works
- You specify a limit of records to return in each request
- The API returns records sorted by the latest first
- To retrieve the next set of records, you use the last record's identifier as a cursor
Pagination Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| limit | integer | No | Number of records to return (default: 10, max: 250) |
| before_shipment_number | string | No | ID of the record to paginate from |
Additionally, you can use filtering parameters along with pagination:
| Parameter | Type | Required | Description |
|---|---|---|---|
| shipment_status_code | string | No | Filter by shipment status |
| date_from | date | No | Start date for filtering (YYYY-MM-DD) |
| date_to | date | No | End date for filtering (YYYY-MM-DD) |
Pagination Example
Initial Request
The first request does not include a before_shipment_number parameter:
{
"limit": 3,
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Subsequent Requests
For the next batch of records, include the before_shipment_number from the last record in the previous response:
{
"limit": 3,
"before_shipment_number": "ES-2504-B944M",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Implementation Guide
Client-Side Pagination Logic
Here's a pseudocode example of how to implement pagination in your client application:
// Initial request - no cursor
let params = {
limit: 20,
shipment_status_code: "7",
date_from: "2025-04-01",
date_to: "2025-04-23"
};
async function fetchAllShipments() {
let allShipments = [];
let hasMoreRecords = true;
while (hasMoreRecords) {
const response = await apiRequest('/shipment/list', params);
// Add fetched shipments to our collection
allShipments = [...allShipments, ...response.data];
// If we received fewer records than requested, we've reached the end
if (response.data.length < params.limit) {
hasMoreRecords = false;
} else {
// Set cursor for next request using the last record's ID
const lastShipment = response.data[response.data.length - 1];
params.before_shipment_number = lastShipment.shipment_number;
}
}
return allShipments;
}
Loading Records On Demand
For user interfaces, you may want to implement "load more" functionality:
let currentParams = {
limit: 20,
shipment_status_code: "7"
};
let shipments = [];
async function loadMoreShipments() {
const response = await apiRequest('/shipment/list', currentParams);
// Add new shipments to the existing list
shipments = [...shipments, ...response.data];
// Update button state
const loadMoreButton = document.getElementById('load-more');
if (response.data.length < currentParams.limit) {
loadMoreButton.style.display = 'none'; // Hide when no more records
} else {
// Update cursor for next request
const lastShipment = response.data[response.data.length - 1];
currentParams.before_shipment_number = lastShipment.shipment_number;
}
// Update UI with new shipments
renderShipments(shipments);
}
Pagination for On-demand Listings
The on-demand listing endpoint (/open_api/2025-06/ondemand/list) follows the same pagination pattern as shipment listings, but uses before_booking_number instead of before_shipment_number:
{
"limit": 3,
"before_booking_number": "EOD-123",
"shipment_status_code": "7",
"date_from": "2025-04-01",
"date_to": "2025-04-23"
}
Best Practices
- Default Limit: If not specified, the API uses a default limit of 10 records per request
- Maximum Limit: The maximum limit is 250 records per request
- Sort Order: Results are always sorted with the most recent records first
- Filter Efficiency: Use status and date filters to reduce the dataset before pagination
- Cursor Storage: Always store the last cursor for error recovery
- Empty Results: If a request returns empty results, you've reached the end of the dataset
Common Issues and Solutions
| Issue | Solution |
|---|---|
| Missing records in pagination sequence | Ensure you're using the correct cursor value |
| Too many API calls for large datasets | Increase the limit parameter (up to 250) |
| Need to restart pagination from beginning | Remove the before_shipment_number parameter |
| Results not matching expected criteria | Review filter parameters for correct formatting |
Notes on Resource Usage
- Using appropriate limit values and filters helps reduce API calls
- Retrieving all records in smaller batches is more reliable than requesting large batches
- Consider implementing caching for frequently accessed records
Switching to Live
If you've completed testing in the DEMO/Sandbox environment and would like to switch to the live environment, please follow the steps below:
- Run the "Get New Access Token" flow.
- Once you reach the "Select Account" section, choose and switch to your live account.
That's it! You have successfully switched to the live environment.