Skip to main content

Work Visit API Testing

This guide provides specific testing approaches and examples for the Equinix Work Visits API, building on the general API Testing principles.

Work Visits API Overview

The Work Visits API allows you to programmatically schedule and manage work visits to Equinix IBX data centers, including:

  • Scheduling work visits for up to 14 days
  • Managing visitor information and access permissions
  • Updating work visit details and contacts
  • Handling cage and cabinet access requirements
  • Managing visitor lists with both registered and non-registered users

Important Note: Work visits are only applicable for visits up to 14 days long. Work visits that exceed 14 days require Security Access approval instead. This service can only be scheduled by a user with IBX Access Services ordering permission.

WorkVisit Testing Workflow

Before testing the Work Visits API, ensure you have:

  • Valid API credentials with work visit ordering permissions
  • Access to Equinix IBX locations where you have cages
  • Valid cage IDs for your work visit locations
  • Understanding of visitor requirements and identification processes

Creating a Work Visit 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 a work visit request
base_url = "https://api.equinix.com/colocations/v2"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}

# Calculate visit dates (future dates)
visit_start = (datetime.utcnow() + timedelta(days=3)).isoformat() + "Z"
visit_end = (datetime.utcnow() + timedelta(days=3, hours=8)).isoformat() + "Z"

# Example: Create a work visit request
work_visit_payload = {
"description": "Monthly routine maintenance and equipment inspection",
"customerReferenceId": "WV-REF-12345",
"purchaseOrder": {
"type": "EXISTING",
"number": "PO-789456"
},
"attachments": [
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "maintenance_checklist.pdf"
}
],
"contacts": [
{
"type": "TECHNICAL",
"registeredUsers": ["tech.admin@example.com"],
"availability": "WORK_HOURS",
"timezone": "America/New_York"
},
{
"type": "NOTIFICATION",
"registeredUsers": ["notifications@example.com"]
}
],
"details": {
"cages": [
{
"id": "SV1:01:001MC3",
"accountNumber": "12345",
"cabinetId": "SV1:01:001MC3:0101"
}
],
"visitStartDateTime": visit_start,
"visitEndDateTime": visit_end,
"openCabinet": True,
"visitors": [
{
"registeredUsers": ["john.doe@example.com"]
},
{
"firstName": "Jane",
"lastName": "Smith",
"companyName": "Acme Corporation",
"details": [
{
"type": "EMAIL",
"value": "jane.smith@acme.com"
},
{
"type": "MOBILE",
"value": "+1-555-123-4567"
}
]
}
]
}
}

create_response = requests.post(
f"{base_url}/orders/workVisits",
headers=headers,
data=json.dumps(work_visit_payload)
)

# Verify response
assert create_response.status_code == 201, f"Failed to create work visit: {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 a Multi-Day Work Visit

# Example: Create a multi-day work visit (up to 14 days)
multi_day_start = (datetime.utcnow() + timedelta(days=5)).isoformat() + "Z"
multi_day_end = (datetime.utcnow() + timedelta(days=12)).isoformat() + "Z"

multi_day_payload = {
"description": "Data center migration project - Phase 1",
"customerReferenceId": "MIGRATION-PHASE1-2025",
"purchaseOrder": {
"type": "NEW",
"number": "PO-MIGRATION-001",
"amount": 5000,
"startDate": "2025-08-01",
"endDate": "2025-12-31"
},
"contacts": [
{
"type": "TECHNICAL",
"registeredUsers": ["migration.lead@example.com"],
"availability": "ANYTIME",
"timezone": "America/Los_Angeles"
}
],
"details": {
"cages": [
{
"id": "LA1:01:002MC5",
"accountNumber": "67890"
},
{
"id": "LA1:01:003MC1",
"accountNumber": "67890"
}
],
"visitStartDateTime": multi_day_start,
"visitEndDateTime": multi_day_end,
"openCabinet": False,
"visitors": [
{
"firstName": "Michael",
"lastName": "Johnson",
"companyName": "Migration Experts Inc",
"details": [
{
"type": "EMAIL",
"value": "mjohnson@migrationexperts.com"
},
{
"type": "MOBILE",
"value": "+1-310-555-9876"
}
]
},
{
"firstName": "Sarah",
"lastName": "Wilson",
"companyName": "Migration Experts Inc",
"details": [
{
"type": "EMAIL",
"value": "swilson@migrationexperts.com"
}
]
}
]
}
}

multi_day_response = requests.post(
f"{base_url}/orders/workVisits",
headers=headers,
data=json.dumps(multi_day_payload)
)

assert multi_day_response.status_code == 201, f"Failed to create multi-day work visit: {multi_day_response.text}"
print("Successfully created multi-day work visit request")

Updating a Work Visit Request

# Test updating work visit details
if order_id:
# Update work visit with new contact information
update_payload = {
"contacts": [
{
"type": "NOTIFICATION",
"registeredUsers": ["updated.notifications@example.com", "backup.contact@example.com"]
}
],
"details": {
"visitStartDateTime": (datetime.utcnow() + timedelta(days=4)).isoformat() + "Z",
"visitEndDateTime": (datetime.utcnow() + timedelta(days=4, hours=6)).isoformat() + "Z",
"openCabinet": False
}
}

update_response = requests.patch(
f"{base_url}/orders/workVisits/{order_id}",
headers=headers,
data=json.dumps(update_payload)
)

# Verify update response
assert update_response.status_code in [202, 204], f"Failed to update work visit: {update_response.text}"
print(f"Successfully updated work visit {order_id}")

Testing Error Scenarios

Always test error handling for your API implementation:

# Test with missing required fields
invalid_payload = {
"description": "Invalid request test",
"details": {
"visitStartDateTime": visit_start,
"visitEndDateTime": visit_end
# Missing required 'cages' and 'visitors' fields
}
}

error_response = requests.post(
f"{base_url}/orders/workVisits",
headers=headers,
data=json.dumps(invalid_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("cages" in error.get("additionalInfo", {}).get("property", "") for error in error_data), "Expected cages validation error"

# Test with invalid visit duration (over 14 days)
long_visit_payload = {
"description": "Invalid long visit test",
"details": {
"cages": [{"id": "SV1:01:001MC3"}],
"visitStartDateTime": visit_start,
"visitEndDateTime": (datetime.utcnow() + timedelta(days=20)).isoformat() + "Z", # Over 14 days
"visitors": [{"registeredUsers": ["test@example.com"]}]
}
}

long_visit_response = requests.post(
f"{base_url}/orders/workVisits",
headers=headers,
data=json.dumps(long_visit_payload)
)

assert long_visit_response.status_code == 400, f"Expected duration validation error but got: {long_visit_response.status_code}"

# Test with invalid cage ID
invalid_cage_payload = {
"description": "Invalid cage test",
"details": {
"cages": [{"id": "INVALID:CAGE:ID"}],
"visitStartDateTime": visit_start,
"visitEndDateTime": visit_end,
"visitors": [{"registeredUsers": ["test@example.com"]}]
}
}

cage_error_response = requests.post(
f"{base_url}/orders/workVisits",
headers=headers,
data=json.dumps(invalid_cage_payload)
)

assert cage_error_response.status_code in [400, 403], f"Expected cage validation error but got: {cage_error_response.status_code}"

Best Practices for Work Visits API Testing

  1. Visit Duration Limits: Always ensure work visits don't exceed 14 days
  2. Valid Cage Access: Verify cage IDs and account permissions before testing
  3. Visitor Information: Test with both registered and non-registered visitors
  4. Contact Validation: Ensure proper contact information and availability settings
  5. Time Zone Handling: Test with different time zones for international locations
  6. Cabinet Access: Test with and without cabinet opening requests
  7. Purchase Order Types: Test all three PO types (NEW, EXISTING, EXEMPTED)
  8. File Attachments: Test attachment uploads for documentation
  9. Permission Validation: Ensure proper IBX Access Services ordering permissions

Automation Considerations

When building automation around the Work Visits API:

  • Implement validation for 14-day maximum visit duration
  • Build in visitor limit validation (50 non-registered visitors maximum)
  • Include proper error handling for cage access and permission issues
  • Implement webhook receivers for work visit status updates
  • Build audit logging for all work visit transactions
  • Validate visitor information completeness before creating requests
  • Ensure proper handling of time zones for international locations
  • Implement proper contact validation for both registered and non-registered users

Additional Resources