Overview
ParcelPanel provides a RESTful API that allows you to programmatically access tracking information for your orders. This documentation covers the API endpoints, request parameters, response formats, and provides examples to help you integrate with ParcelPanel.
Base URL
All API requests should be made to the following base URL:
https://open.parcelpanel.com
Authentication
Authentication is required for all API requests. You need to include your API key in the request header.
x-parcelpanel-api-key: YOUR_API_KEY
Endpoints
Order Tracking
Retrieves tracking information for a specific order.
Endpoint: /api/v2/tracking/order
Method: GET
Request Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
order_number | string | No* | The order number (e.g., "#1034") |
order_id | string | No* | The order ID (e.g., "6126773010750") |
*At least one of these parameters must be provided.
Response:
When successful, the API returns a JSON object with tracking details.
Success Response (200 OK):
{
"order": {
"order_id": 6140516335690,
"order_number": "#1030",
"order_tags": [
"ParcelPanel",
"API2.0"
],
"store": {
"name": "Example Store",
"url": "https://example.myshopify.com"
},
"customer": {
"name": "Aaliyah Bins",
"email": "[email protected]",
"phone": "12345678901"
},
"shipping_address": {
"name": "Aaliyah Bins",
"phone": null,
"country": "United States",
"country_code": "US",
"province": "California",
"province_code": "CA",
"city": "Mountain View",
"zip": "94043",
"address1": "1600 Amphitheatre Parkway",
"address2": null,
"company": "Googleplex"
},
"tracking_link": "https://example.myshopify.com/apps/parcelpanel-test?order=1030&token=gro.elpmaxe_-_namllit.enelym",
"shipments": [
{
"status": "DELIVERED",
"status_label": "Delivered",
"substatus": "Delivered_001",
"substatus_label": "Delivered",
"tracking_number": "YT2436021211003147",
"carrier": {
"name": "YunExpress",
"code": "yunexpress",
"contact": "400-8575-500",
"logo_url": "https://cdn.parcelpanel.com/assets/common/images/express/yunexpress.png",
"url": "http://www.yuntrack.com/track/detail?id=YT2436021211003147"
},
"transit_time": 11,
"residence_time": 1,
"estimated_delivery_date": {
"source": "CUSTOM",
"display_text": "Jan 12, 2025 - Jan 16, 2025"
},
"order_date": "2024-12-23T01:02:40+00:00",
"fulfillment_date": "2024-12-24T01:25:40+00:00",
"pickup_date": "2025-01-03T01:28:40",
"delivery_date": "2025-01-13T14:36:00",
"last_mile_tracking_supported": true,
"last_mile": {
"carrier_name": "USPS",
"carrier_code": "usps",
"tracking_number": "9261290358097849005373",
"carrier_contact": "1 800-275-8777",
"carrier_logo_url": "https://cdn.parcelpanel.com/assets/common/images/express/usps.png",
"carrier_url": "https://tools.usps.com/go/TrackConfirmAction?qtc_tLabels1=9261290358097849005373"
},
"products": [
{
"id": 6941337714762,
"title": "Amazing Aluminum Bag Collection10",
"variant_id": 39969756151882,
"variant_title": "xs / red / water",
"quantity": 3,
"image_url": "https://cdn.shopify.com/s/files/1/0563/3435/2458/products/AAUvwnj0ICORVuxs41ODOvnhvedArLiSV20df7r8XBjEUQ_s900-c-k-c0x00ffffff-no-rj_147ad8db-b4f4-40a5-b751-c0a8428b8ae7-951612.jpg?v=1678447639",
"url": "https://example.myshopify.com/apps/parcelpanel/bland?q=eyJ0IjoxNzQ1NTY1MzAzLCJwcm9kdWN0X2lkIjo2OTQxMzM3NzE0NzYyLCJoYW5kbGUiOiJhbWF6aW5nLWFsdW1pbnVtLWJhZy1jb2xsZWN0aW9uMTAiLCJmcm9tIjoicGFyY2VscGFuZWwtYWRtaW4ifQ"
}
],
"checkpoints": [
{
"detail": "Delivered, In/At Mailbox, FAIRBANKS, AK 99701",
"status": "DELIVERED",
"status_label": "Delivered",
"substatus": "Delivered_001",
"substatus_label": "Delivered",
"checkpoint_time": "2025-01-13T14:36:00"
},
{
"detail": "Out for Delivery, FAIRBANKS, AK 99701",
"status": "OUT_FOR_DELIVERY",
"status_label": "Out for delivery",
"substatus": "OutForDelivery_001",
"substatus_label": "Out for delivery",
"checkpoint_time": "2025-01-13T06:45:00"
}
]
}
]
}
}
Error Response (404 Not Found):
{
"errors": "Order not found"
}
Response Object Definitions
Order Object
Field | Type | Nullable | Description |
---|---|---|---|
order_id | integer | No | Unique identifier for the order |
order_number | string | No | The order number displayed to customers |
order_tags | array | No | Array of tags associated with the order |
store | object | No | Information about the store |
customer | object | No | Information about the customer |
shipping_address | object | Yes | Shipping address information |
tracking_link | string | No | Link to track the order |
shipments | array | No | Array of shipment objects |
Store Object
Field | Type | Nullable | Description |
---|---|---|---|
name | string | No | Store name |
url | string | No | Store URL |
Customer Object
Field | Type | Nullable | Description |
---|---|---|---|
name | string | Yes | Customer name |
string | Yes | Customer email address | |
phone | string | Yes | Customer phone number |
Shipping Address Object
Field | Type | Nullable | Description |
---|---|---|---|
name | string | Yes | Recipient name |
phone | string | Yes | Recipient phone number |
country | string | Yes | Country name |
country_code | string | Yes | Country code (ISO format) |
province | string | Yes | Province or state name |
province_code | string | Yes | Province or state code |
city | string | Yes | City name |
zip | string | Yes | ZIP or postal code |
address1 | string | Yes | Address line 1 |
address2 | string | Yes | Address line 2 |
company | string | Yes | Company name |
Shipment Object
Field | Type | Nullable | Description |
---|---|---|---|
status | string | No | Main status code (PENDING, INFO_RECEIVED, IN_TRANSIT, OUT_FOR_DELIVERY, READY_FOR_PICKUP, DELIVERED, EXCEPTION, FAILED_ATTEMPT, EXPIRED) |
status_label | string | No | Human-readable main status |
substatus | string | No | Detailed status code |
substatus_label | string | No | Human-readable detailed status |
tracking_number | string | No | Tracking number for the shipment |
carrier | object | Yes | Information about the carrier |
transit_time | integer | No | Transit time in days |
residence_time | integer | Yes | Residence time in days |
estimated_delivery_date | object | Yes | Estimated delivery date information |
order_date | string | No | Date when the order was placed (ISO 8601 format) |
fulfillment_date | string | Yes | Date when the order was fulfilled (ISO 8601 format) |
pickup_date | string | Yes | Date when the package was picked up (ISO 8601 format) |
delivery_date | string | Yes | Date when the package was delivered (ISO 8601 format) |
last_mile_tracking_supported | boolean | No | Whether last mile tracking is supported |
last_mile | object | Yes | Information about the last mile carrier |
products | array | No | Products included in the shipment |
checkpoints | array | No | Array of checkpoint objects showing the package's journey |
Carrier Object
Field | Type | Nullable | Description |
---|---|---|---|
name | string | No | Carrier name |
code | string | No | Carrier code (see carrier list) |
url | string | No | Tracking URL for the carrier |
logo_url | string | No | URL to the carrier's logo |
contact | string | No | Contact information for the carrier |
Last Mile Carrier Object
Field | Type | Nullable | Description |
---|---|---|---|
carrier_name | string | No | Last mile carrier name |
carrier_code | string | No | Last mile carrier code |
tracking_number | string | No | Last mile tracking number |
carrier_contact | string | Yes | Contact information for the last mile carrier |
carrier_logo_url | string | Yes | URL to the last mile carrier's logo |
carrier_url | string | Yes | Tracking URL for the last mile carrier |
Product Object
Field | Type | Nullable | Description |
---|---|---|---|
id | integer | Yes | Product ID |
title | string | No | Product title |
variant_id | integer | Yes | Variant ID |
variant_title | string | Yes | Variant title |
quantity | integer | No | Quantity of the product |
image_url | string | Yes | URL to the product image |
url | string | Yes | URL to the product page |
Checkpoint Object
Field | Type | Nullable | Description |
---|---|---|---|
detail | string | No | Detailed description of the checkpoint |
status | string | Yes | Status code at this checkpoint |
status_label | string | Yes | Human-readable status |
substatus | string | Yes | Detailed status code |
substatus_label | string | Yes | Human-readable detailed status |
checkpoint_time | string | No | Time of the checkpoint (ISO 8601 format) |
Estimated Delivery Date Object
Field | Type | Nullable | Description |
---|---|---|---|
source | string | No | Source of the estimated delivery date (SHOPIFY, CARRIER, CUSTOM) |
display_text | string | No | Human-readable display text for the estimated delivery date |
Enumeration Values
Main Status Codes
The status
field in shipments and checkpoints can have the following values:
Code | Description |
---|---|
PENDING | Shipment is pending, not yet processed |
INFO_RECEIVED | Shipping information has been received |
IN_TRANSIT | Package is in transit |
OUT_FOR_DELIVERY | Package is out for delivery |
READY_FOR_PICKUP | Package is ready for pickup |
DELIVERED | Package has been delivered |
EXCEPTION | An issue has occurred with the shipment |
FAILED_ATTEMPT | Delivery attempt failed |
EXPIRED | Tracking has expired |
Sub Status Codes
The substatus
field provides more detailed information about the shipment status:
Code | Main Status | Description |
---|---|---|
Pending_001 | PENDING | Pending |
Pending_002 | PENDING | Order processed |
InfoReceived_001 | INFO_RECEIVED | Shipping information received |
InTransit_001 | IN_TRANSIT | In transit |
InTransit_002 | IN_TRANSIT | Departed from facility |
InTransit_003 | IN_TRANSIT | Arrived at facility |
InTransit_004 | IN_TRANSIT | Customs clearance completed |
InTransit_005 | IN_TRANSIT | Customs clearance delay |
InTransit_006 | IN_TRANSIT | In transit to next facility |
InTransit_007 | IN_TRANSIT | International shipment release |
OutForDelivery_001 | OUT_FOR_DELIVERY | Out for delivery |
OutForDelivery_002 | OUT_FOR_DELIVERY | Out for delivery again |
ReadyForPickup_001 | READY_FOR_PICKUP | Ready for pickup |
Delivered_001 | DELIVERED | Delivered |
Delivered_002 | DELIVERED | Delivered to agent |
Delivered_003 | DELIVERED | Delivered to neighbor |
Delivered_004 | DELIVERED | Delivered to pickup point |
Exception_001 | EXCEPTION | Unknown exception |
Exception_002 | EXCEPTION | Delivery exception |
Exception_003 | EXCEPTION | Returned to sender |
Exception_004 | EXCEPTION | Address issue |
Exception_005 | EXCEPTION | Damaged |
Exception_006 | EXCEPTION | Lost |
Exception_007 | EXCEPTION | Held at customs |
Exception_008 | EXCEPTION | Delivery rescheduled |
FailedAttempt_001 | FAILED_ATTEMPT | Failed attempt |
FailedAttempt_002 | FAILED_ATTEMPT | Recipient not available |
FailedAttempt_003 | FAILED_ATTEMPT | Office closed |
FailedAttempt_004 | FAILED_ATTEMPT | Weather delay |
Expired_001 | EXPIRED | Tracking expired |
Estimated Delivery Date Source
The source
field in the estimated_delivery_date
object can have the following values:
Code | Description |
---|---|
SHOPIFY | Estimated delivery date from Shopify |
CARRIER | Estimated delivery date from the carrier |
CUSTOM | Custom estimated delivery date |
Code Examples
cURL
curl -X GET "https://open.parcelpanel.com/api/v2/tracking/order?order_number=1030" \
-H "x-parcelpanel-api-key: YOUR_API_KEY"
Python
import requests
url = "https://open.parcelpanel.com/api/v2/tracking/order"
headers = {
"x-parcelpanel-api-key": "YOUR_API_KEY"
}
params = {
"order_number": "1030"
}
response = requests.get(url, headers=headers, params=params)
print(response.json())
Node.js
const axios = require('axios');
const options = {
method: 'GET',
url: 'https://open.parcelpanel.com/api/v2/tracking/order',
params: {
order_number: '1030'
},
headers: {
'x-parcelpanel-api-key': 'YOUR_API_KEY'
}
};
axios.request(options)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
PHP
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://open.parcelpanel.com/api/v2/tracking/order?order_number=1030",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-parcelpanel-api-key: YOUR_API_KEY"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
?>
Go
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// Create a new request
req, err := http.NewRequest("GET", "https://open.parcelpanel.com/api/v2/tracking/order", nil)
if err != nil {
fmt.Println("Error creating request:", err)
return
}
// Add query parameters
q := req.URL.Query()
q.Add("order_number", "1030")
req.URL.RawQuery = q.Encode()
// Add headers
req.Header.Add("x-parcelpanel-api-key", "YOUR_API_KEY")
// Send the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error sending request:", err)
return
}
defer resp.Body.Close()
// Read the response body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
// Print the response
fmt.Println(string(body))
}
Java
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ParcelPanelApiExample {
public static void main(String[] args) {
try {
// Create URL with query parameters
URL url = new URL("https://open.parcelpanel.com/api/v2/tracking/order?order_number=1030");
// Open connection
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Set request method
connection.setRequestMethod("GET");
// Set headers
connection.setRequestProperty("x-parcelpanel-api-key", "YOUR_API_KEY");
// Get response code
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
// Read response
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// Print response
System.out.println(response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
C#
using System;
using System.Net.Http;
using System.Threading.Tasks;
class ParcelPanelApiExample
{
static async Task Main()
{
// Create HttpClient
using (HttpClient client = new HttpClient())
{
// Set base address
client.BaseAddress = new Uri("https://open.parcelpanel.com");
// Add headers
client.DefaultRequestHeaders.Add("x-parcelpanel-api-key", "YOUR_API_KEY");
try
{
// Send request
HttpResponseMessage response = await client.GetAsync("/api/v2/tracking/order?order_number=1030");
// Ensure successful response
response.EnsureSuccessStatusCode();
// Read response content
string responseContent = await response.Content.ReadAsStringAsync();
// Output response
Console.WriteLine(responseContent);
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
}
}
Ruby
require 'net/http'
require 'uri'
require 'json'
# Set the URL
uri = URI.parse('https://open.parcelpanel.com/api/v2/tracking/order')
# Add query parameters
params = { order_number: '1030' }
uri.query = URI.encode_www_form(params)
# Create HTTP request
request = Net::HTTP::Get.new(uri)
# Add headers
request['x-parcelpanel-api-key'] = 'YOUR_API_KEY'
# Create HTTP connection
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
begin
# Send the request
response = http.request(request)
# Check if response was successful
if response.code == '200'
# Parse and print the JSON response
result = JSON.parse(response.body)
puts result
else
puts "Error: #{response.code} - #{response.message}"
end
rescue => e
puts "Exception: #{e.message}"
end
Rate Limits
The API enforces rate limits to ensure service stability and fair usage across all users. The current rate limit is:
- 4 requests per second per API key
If you exceed the rate limit, the API will return a 429 Too Many Requests
status code. In this case, you should implement an exponential backoff strategy in your application.
Need higher limits? If your application requires a higher rate limit, please contact ParcelPanel Support at [email protected] to discuss your specific needs.
Error Codes
Status Code | Description |
---|---|
400 | Bad Request - Your request is invalid |
401 | Unauthorized - Your API key is wrong |
404 | Not Found - The requested resource could not be found |
422 | Unprocessable Entity - The parameters were valid but the request failed due to semantic errors |
429 | Too Many Requests - You have exceeded the rate limit |
500 | Internal Server Error - We had a problem with our server |
Support
For any questions or issues regarding the API, please contact our support team at [email protected].