Shipment API Testing
This guide provides specific testing approaches and examples for the Equinix Shipments API, building on the general API Testing principles.
Shipments API Overview
The Shipments API allows you to programmatically schedule and manage inbound and outbound shipments to Equinix IBX data centers, including:
- Scheduling inbound shipments (receiving packages)
- Scheduling outbound shipments (sending packages)
- Updating shipment details
- Managing shipment tracking information
- Handling carrier information and tracking numbers
Important Note: All inbound and outbound shipments must be scheduled 24 hours in advance. The Equinix API is a production system that creates real shipment requests. Always follow these testing best practices to ensure you don't create unintended operational work.
Shipment Testing Workflow
Before testing the Shipments API, ensure you have:
- Valid API credentials with shipments ordering permissions
- Access to Equinix IBX locations where you have cages
- Valid cage IDs for your shipment locations
- Understanding of carrier requirements and tracking number formats
Creating an Inbound Shipment Request
import requests
import json
from datetime import datetime, timedelta
# Setup authentication
auth_url = "https://api.equinix.com/oauth2/v1/token"
auth_payload = {
"grant_type": "client_credentials",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
}
auth_response = requests.post(auth_url, data=auth_payload)
token = auth_response.json()["access_token"]
# Test creating an inbound shipment request
base_url = "https://api.equinix.com/colocations/v2"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
# Calculate delivery date (24+ hours in advance as required)
delivery_date = (datetime.utcnow() + timedelta(days=2)).isoformat() + "Z"
# Example: Create an inbound shipment request
inbound_payload = {
"type": "INBOUND",
"requestedDateTime": delivery_date,
"cageId": "SV1:01:001MC3",
"customerReferenceId": "SHIP-REF-12345",
"description": "Server hardware delivery for data center expansion project",
"details": {
"carrier": "DHL",
"carrierTrackingNumbers": [
"1234567890123",
"1234567890124"
],
"numberOfBoxes": 2,
"accountNumber": "12345"
},
"purchaseOrder": {
"type": "EXISTING",
"number": "PO-789456"
},
"attachments": [
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "packing_list.pdf"
}
],
"contacts": [
{
"type": "TECHNICAL",
"registeredUsers": ["tech.admin@example.com"],
"availability": "WORK_HOURS",
"timezone": "America/New_York"
},
{
"type": "NOTIFICATION",
"registeredUsers": ["notifications@example.com"]
}
]
}
create_response = requests.post(
f"{base_url}/orders/shipments",
headers=headers,
data=json.dumps(inbound_payload)
)
# Verify response
assert create_response.status_code == 201, f"Failed to create shipment: {create_response.text}"
# Extract order ID from Location header
order_number = create_response.json()["OrderNumber"]
print(f"Successfully created inbound shipment with order ID: {order_number}")
Creating an Outbound Shipment Request
# Example: Create an outbound shipment request
outbound_payload = {
"type": "OUTBOUND",
"requestedDateTime": delivery_date,
"cageId": "SV1:01:001MC3",
"customerReferenceId": "OUT-SHIP-67890",
"description": "Returning defective network equipment to vendor",
"details": {
"carrier": "FEDEX",
"carrierTrackingNumbers": [
"987654321098"
],
"numberOfBoxes": 1,
"pickupLocation": "Main cage entrance",
"specialInstructions": "Handle with care - contains sensitive electronic equipment"
},
"purchaseOrder": {
"type": "EXEMPTED"
},
"contacts": [
{
"type": "TECHNICAL",
"registeredUsers": ["shipping@example.com"],
"availability": "ANYTIME"
}
]
}
outbound_response = requests.post(
f"{base_url}/orders/shipments",
headers=headers,
data=json.dumps(outbound_payload)
)
assert outbound_response.status_code == 201, f"Failed to create outbound shipment: {outbound_response.text}"
order_number = outbound_response.json()["OrderNumber"]
print("Successfully created outbound shipment request with order ID: {order_number}")
Testing Error Scenarios
Always test error handling for your API implementation:
# Test with invalid carrier
invalid_carrier_payload = {
"type": "INBOUND",
"requestedDateTime": delivery_date,
"cageId": "SV1:01:001MC3",
"details": {
"carrier": "INVALID_CARRIER", # Invalid carrier
"carrierTrackingNumbers": ["1234567890"],
"numberOfBoxes": 1
},
"contacts": [
{
"type": "TECHNICAL",
"registeredUsers": ["test@example.com"]
}
]
}
error_response = requests.post(
f"{base_url}/orders/shipments",
headers=headers,
data=json.dumps(invalid_carrier_payload)
)
# Verify error response
assert error_response.status_code == 400, f"Expected error but got: {error_response.status_code}"
error_data = error_response.json()
assert any("carrier" in error["errorMessage"].lower() for error in error_data), "Expected carrier validation error"
# Test with insufficient advance notice (less than 24 hours)
insufficient_time_payload = {
"type": "INBOUND",
"requestedDateTime": (datetime.utcnow() + timedelta(hours=12)).isoformat() + "Z", # Only 12 hours advance
"cageId": "SV1:01:001MC3",
"details": {
"carrier": "DHL",
"carrierTrackingNumbers": ["1234567890"],
"numberOfBoxes": 1
},
"contacts": [
{
"type": "TECHNICAL",
"registeredUsers": ["test@example.com"]
}
]
}
time_error_response = requests.post(
f"{base_url}/orders/shipments",
headers=headers,
data=json.dumps(insufficient_time_payload)
)
assert time_error_response.status_code == 400, f"Expected time validation error but got: {time_error_response.status_code}"
Best Practices for Shipments API Testing
- 24-Hour Advance Rule: Always schedule shipments at least 24 hours in advance
- Valid Tracking Numbers: Use realistic tracking number formats for each carrier
- Proper Contact Information: Ensure contacts are available during delivery windows
- Cage Access: Verify cage IDs and access permissions before testing
- International Shipments: Consider customs requirements for international deliveries
- Special Instructions: Test with various special handling requirements
- File Attachments: Test attachment uploads for packing lists and special instructions
- Time Zones: Handle time zone conversions properly for scheduling
- Purchase Orders: Test different PO types (NEW, EXISTING, EXEMPTED)
Automation Considerations
When building automation around the Shipments API:
- Implement validation for the 24-hour advance scheduling requirement
- Build in carrier-specific validation for tracking number formats
- Include proper error handling for carrier availability and capacity issues
- Implement webhook receivers for shipment status updates
- Build audit logging for all shipment transactions
- Validate cage access and permissions before creating requests
- Ensure proper handling of time zones for international locations