Get Work Order Details
The Get Work Order Details endpoint retrieves comprehensive information about a specific work order, including related data such as call logs, inspections, and team assignments.
Endpoint
GET /api/v1/external/workorders/{id}/
Full URL: https://app.centroaccess.com/api/v1/external/workorders/{id}/
Authentication
Requires API key with view_workorder permission.
Authorization: Api-Key your-api-key-here
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Unique work order identifier |
Response Format
Success Response (200 OK)
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Install fiber connection",
"client_name": "John Doe",
"client_contact": "+1234567890",
"additional_information": "Customer prefers morning appointments",
"status": "in_progress",
"status_display": "In Progress",
"priority": "high",
"priority_display": "High",
"service_category": "installation",
"service_category_display": "Installation",
"queue_type": "priority",
"due_date": "2025-12-31",
"preferred_time": "2025-10-25T10:00:00Z",
"niceness": 0,
"call_attempts": 2,
"last_status_change": "2025-10-23T15:00:00Z",
"completed_at": null,
"longitude": -73.935242,
"latitude": 40.730610,
"created_at": "2025-10-23T14:30:00Z",
"updated_at": "2025-10-23T15:00:00Z",
"is_overdue": false,
"assigned_at": "2025-10-23T14:45:00Z",
"service_zone": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Downtown Area",
"description": "Central business district"
},
"assigned_team": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"name": "Installation Team A",
"description": "Primary installation team"
},
"created_by": {
"id": "880e8400-e29b-41d4-a716-446655440003",
"email": "api-key-system@centroaccess.com",
"name": "API Key: Integration System"
},
"call_logs": [
{
"id": 1,
"call_time": "2025-10-23T14:35:00Z",
"notes": "Customer confirmed appointment time",
"outcome": "successful"
},
{
"id": 2,
"call_time": "2025-10-23T16:20:00Z",
"notes": "Rescheduled to tomorrow morning",
"outcome": "rescheduled"
}
],
"inspections": [
{
"id": "990e8400-e29b-41d4-a716-446655440004",
"inspection_type": "pre_installation",
"status": "completed",
"completed_at": "2025-10-23T13:00:00Z",
"notes": "Site ready for installation"
}
],
"child_work_orders": [],
"next_possible_status": ["assigned", "on_hold", "cancelled", "completed"]
}
Work Order Fields
| Field | Type | Description |
|---|---|---|
id | UUID | Unique work order identifier |
title | string | Work order title |
client_name | string | Customer/client name |
client_contact | string | Client phone number |
additional_information | string | Additional notes and information |
status | string | Current status code |
status_display | string | Human-readable status |
priority | string | Priority level code |
priority_display | string | Human-readable priority |
service_category | string | Service category code |
service_category_display | string | Human-readable category |
queue_type | string | Queue classification |
due_date | string/null | Due date (YYYY-MM-DD) |
preferred_time | string/null | Preferred appointment time (ISO format) |
niceness | integer | Priority adjustment value |
call_attempts | integer | Number of customer contact attempts |
last_status_change | string | Timestamp of last status change |
completed_at | string/null | Completion timestamp |
longitude | float/null | Longitude coordinate |
latitude | float/null | Latitude coordinate |
created_at | string | Creation timestamp |
updated_at | string | Last update timestamp |
is_overdue | boolean | Whether the work order is overdue |
assigned_at | string/null | Team assignment timestamp |
Related Data Fields
| Field | Type | Description |
|---|---|---|
service_zone | object/null | Service zone information |
assigned_team | object/null | Assigned team details |
created_by | object | User who created the work order |
call_logs | array | Customer contact history |
inspections | array | Related inspection records |
child_work_orders | array | Related child work orders |
next_possible_status | array | Available status transitions |
Examples
Basic Request
Get details for a specific work order:
curl -X GET "https://app.centroaccess.com/api/v1/external/workorders/550e8400-e29b-41d4-a716-446655440000/" \
-H "Authorization: Api-Key your-api-key-here"
Using Environment Variables
export API_KEY="your-api-key-here"
export WORK_ORDER_ID="550e8400-e29b-41d4-a716-446655440000"
curl -X GET "https://app.centroaccess.com/api/v1/external/workorders/$WORK_ORDER_ID/" \
-H "Authorization: Api-Key $API_KEY"
Call Logs
Call logs track all customer contact attempts:
| Field | Type | Description |
|---|---|---|
id | integer | Unique call log identifier |
call_time | string | Timestamp of the call |
notes | string | Notes about the call |
outcome | string | Call outcome (successful, no_answer, rescheduled, etc.) |
Call Outcome Values
| Outcome | Description |
|---|---|
successful | Call was successful |
no_answer | No answer from customer |
voicemail | Left voicemail |
busy | Line was busy |
rescheduled | Appointment rescheduled |
cancelled | Customer cancelled |
wrong_number | Wrong phone number |
Inspections
Inspection records show related quality checks:
| Field | Type | Description |
|---|---|---|
id | UUID | Unique inspection identifier |
inspection_type | string | Type of inspection |
status | string | Inspection status |
completed_at | string/null | Completion timestamp |
notes | string | Inspection notes |
Inspection Types
| Type | Description |
|---|---|
pre_installation | Pre-installation survey |
post_installation | Post-installation quality check |
maintenance | Routine maintenance inspection |
troubleshooting | Problem investigation |
Inspection Status Values
| Status | Description |
|---|---|
pending | Not yet started |
in_progress | Currently being performed |
completed | Successfully completed |
failed | Failed inspection |
cancelled | Cancelled inspection |
Error Responses
Work Order Not Found
Status Code: 404 Not Found
{
"error": "Work order not found"
}
Invalid UUID Format
Status Code: 400 Bad Request
{
"error": "Invalid UUID format"
}
Authentication Required
Status Code: 401 Unauthorized
{
"detail": "Invalid API key"
}
Insufficient Permissions
Status Code: 403 Forbidden
{
"error": "Insufficient permissions",
"required_permission": "workorder.view_workorder"
}
Server Error
Status Code: 500 Internal Server Error
{
"error": "Failed to retrieve work order",
"details": "Unexpected error occurred"
}
Code Examples
Python
import requests
from datetime import datetime
API_KEY = "your-api-key-here"
BASE_URL = "https://app.centroaccess.com/api/v1/external"
headers = {
"Authorization": f"Api-Key {API_KEY}",
"Content-Type": "application/json"
}
def get_work_order_details(work_order_id):
"""Get detailed information about a work order."""
response = requests.get(
f"{BASE_URL}/workorders/{work_order_id}/",
headers=headers
)
if response.status_code == 200:
work_order = response.json()
print(f"📋 Work Order: {work_order['title']}")
print(f" ID: {work_order['id']}")
print(f" Status: {work_order['status_display']}")
print(f" Priority: {work_order['priority_display']}")
print(f" Client: {work_order['client_name']} ({work_order['client_contact']})")
print(f" Created: {work_order['created_at']}")
if work_order['assigned_team']:
print(f" Team: {work_order['assigned_team']['name']}")
if work_order['service_zone']:
print(f" Zone: {work_order['service_zone']['name']}")
# Call logs
if work_order['call_logs']:
print(f"\n📞 Call History ({len(work_order['call_logs'])} calls):")
for call in work_order['call_logs']:
print(f" - {call['call_time']}: {call['notes']} ({call['outcome']})")
# Inspections
if work_order['inspections']:
print(f"\n🔍 Inspections ({len(work_order['inspections'])}):")
for inspection in work_order['inspections']:
print(f" - {inspection['inspection_type']}: {inspection['status']}")
if inspection['notes']:
print(f" Notes: {inspection['notes']}")
return work_order
elif response.status_code == 404:
print(f"❌ Work order {work_order_id} not found")
return None
else:
print(f"❌ Error: {response.status_code} - {response.text}")
return None
def check_work_order_status(work_order_id):
"""Check if a work order is completed or overdue."""
work_order = get_work_order_details(work_order_id)
if not work_order:
return None
status_info = {
"id": work_order["id"],
"status": work_order["status"],
"is_completed": work_order["status"] == "completed",
"is_overdue": work_order["is_overdue"],
"completed_at": work_order["completed_at"],
"next_possible_status": work_order["next_possible_status"]
}
return status_info
def get_work_order_timeline(work_order_id):
"""Get a timeline of work order events."""
work_order = get_work_order_details(work_order_id)
if not work_order:
return []
timeline = []
# Creation
timeline.append({
"timestamp": work_order["created_at"],
"event": "Created",
"details": f"Work order created: {work_order['title']}"
})
# Assignment
if work_order["assigned_at"]:
team_name = work_order["assigned_team"]["name"] if work_order["assigned_team"] else "Unknown"
timeline.append({
"timestamp": work_order["assigned_at"],
"event": "Assigned",
"details": f"Assigned to team: {team_name}"
})
# Status changes
if work_order["last_status_change"]:
timeline.append({
"timestamp": work_order["last_status_change"],
"event": "Status Change",
"details": f"Status changed to: {work_order['status_display']}"
})
# Call logs
for call in work_order["call_logs"]:
timeline.append({
"timestamp": call["call_time"],
"event": "Customer Contact",
"details": f"{call['outcome']}: {call['notes']}"
})
# Inspections
for inspection in work_order["inspections"]:
if inspection["completed_at"]:
timeline.append({
"timestamp": inspection["completed_at"],
"event": "Inspection",
"details": f"{inspection['inspection_type']}: {inspection['status']}"
})
# Sort by timestamp
timeline.sort(key=lambda x: x["timestamp"])
return timeline
# Usage examples
work_order = get_work_order_details("550e8400-e29b-41d4-a716-446655440000")
status = check_work_order_status("550e8400-e29b-41d4-a716-446655440000")
timeline = get_work_order_timeline("550e8400-e29b-41d4-a716-446655440000")
print("\n⏰ Timeline:")
for event in timeline:
print(f" {event['timestamp']}: {event['event']} - {event['details']}")
JavaScript/Node.js
const axios = require('axios');
const API_KEY = 'your-api-key-here';
const BASE_URL = 'https://app.centroaccess.com/api/v1/external';
const headers = {
'Authorization': `Api-Key ${API_KEY}`,
'Content-Type': 'application/json'
};
async function getWorkOrderDetails(workOrderId) {
try {
const response = await axios.get(
`${BASE_URL}/workorders/${workOrderId}/`,
{ headers }
);
const workOrder = response.data;
console.log(`📋 Work Order: ${workOrder.title}`);
console.log(` ID: ${workOrder.id}`);
console.log(` Status: ${workOrder.status_display}`);
console.log(` Priority: ${workOrder.priority_display}`);
console.log(` Client: ${workOrder.client_name} (${workOrder.client_contact})`);
console.log(` Created: ${workOrder.created_at}`);
if (workOrder.assigned_team) {
console.log(` Team: ${workOrder.assigned_team.name}`);
}
if (workOrder.service_zone) {
console.log(` Zone: ${workOrder.service_zone.name}`);
}
// Call logs
if (workOrder.call_logs.length > 0) {
console.log(`\n📞 Call History (${workOrder.call_logs.length} calls):`);
workOrder.call_logs.forEach(call => {
console.log(` - ${call.call_time}: ${call.notes} (${call.outcome})`);
});
}
// Inspections
if (workOrder.inspections.length > 0) {
console.log(`\n🔍 Inspections (${workOrder.inspections.length}):`);
workOrder.inspections.forEach(inspection => {
console.log(` - ${inspection.inspection_type}: ${inspection.status}`);
if (inspection.notes) {
console.log(` Notes: ${inspection.notes}`);
}
});
}
return workOrder;
} catch (error) {
if (error.response?.status === 404) {
console.log(`❌ Work order ${workOrderId} not found`);
} else {
console.error('❌ Error getting work order details:', error.response?.data || error.message);
}
return null;
}
}
async function checkWorkOrderStatus(workOrderId) {
const workOrder = await getWorkOrderDetails(workOrderId);
if (!workOrder) return null;
return {
id: workOrder.id,
status: workOrder.status,
isCompleted: workOrder.status === 'completed',
isOverdue: workOrder.is_overdue,
completedAt: workOrder.completed_at,
nextPossibleStatus: workOrder.next_possible_status
};
}
async function getWorkOrderTimeline(workOrderId) {
const workOrder = await getWorkOrderDetails(workOrderId);
if (!workOrder) return [];
const timeline = [];
// Creation
timeline.push({
timestamp: workOrder.created_at,
event: 'Created',
details: `Work order created: ${workOrder.title}`
});
// Assignment
if (workOrder.assigned_at) {
const teamName = workOrder.assigned_team?.name || 'Unknown';
timeline.push({
timestamp: workOrder.assigned_at,
event: 'Assigned',
details: `Assigned to team: ${teamName}`
});
}
// Status changes
if (workOrder.last_status_change) {
timeline.push({
timestamp: workOrder.last_status_change,
event: 'Status Change',
details: `Status changed to: ${workOrder.status_display}`
});
}
// Call logs
workOrder.call_logs.forEach(call => {
timeline.push({
timestamp: call.call_time,
event: 'Customer Contact',
details: `${call.outcome}: ${call.notes}`
});
});
// Inspections
workOrder.inspections.forEach(inspection => {
if (inspection.completed_at) {
timeline.push({
timestamp: inspection.completed_at,
event: 'Inspection',
details: `${inspection.inspection_type}: ${inspection.status}`
});
}
});
// Sort by timestamp
timeline.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
return timeline;
}
async function monitorWorkOrder(workOrderId, interval = 60000) {
console.log(`🔄 Monitoring work order ${workOrderId}...`);
let lastStatus = null;
const checkStatus = async () => {
const status = await checkWorkOrderStatus(workOrderId);
if (status && status.status !== lastStatus) {
console.log(`📱 Status update: ${status.status} (was: ${lastStatus || 'unknown'})`);
lastStatus = status.status;
if (status.isCompleted) {
console.log(`✅ Work order completed at ${status.completedAt}`);
return true; // Stop monitoring
}
if (status.isOverdue) {
console.log(`⚠️ Work order is overdue!`);
}
}
return false; // Continue monitoring
};
// Initial check
const shouldStop = await checkStatus();
if (shouldStop) return;
// Set up interval
const intervalId = setInterval(async () => {
const shouldStop = await checkStatus();
if (shouldStop) {
clearInterval(intervalId);
}
}, interval);
}
// Usage examples
async function examples() {
const workOrderId = '550e8400-e29b-41d4-a716-446655440000';
// Get details
const workOrder = await getWorkOrderDetails(workOrderId);
// Check status
const status = await checkWorkOrderStatus(workOrderId);
console.log('Status:', status);
// Get timeline
const timeline = await getWorkOrderTimeline(workOrderId);
console.log('\n⏰ Timeline:');
timeline.forEach(event => {
console.log(` ${event.timestamp}: ${event.event} - ${event.details}`);
});
// Monitor (uncomment to enable)
// await monitorWorkOrder(workOrderId);
}
examples();
Use Cases
1. Status Monitoring
Monitor work order progress and get notified of status changes:
def monitor_work_orders(work_order_ids):
"""Monitor multiple work orders for status changes."""
status_cache = {}
for wo_id in work_order_ids:
current_status = check_work_order_status(wo_id)
if wo_id in status_cache:
if current_status['status'] != status_cache[wo_id]['status']:
print(f"🔄 Status change for {wo_id}: {status_cache[wo_id]['status']} → {current_status['status']}")
status_cache[wo_id] = current_status
if current_status['is_completed']:
print(f"✅ Work order {wo_id} completed!")
elif current_status['is_overdue']:
print(f"⚠️ Work order {wo_id} is overdue!")
2. Progress Reporting
Generate progress reports for management:
def generate_work_order_report(work_order_ids):
"""Generate a comprehensive report for multiple work orders."""
report = {
"total": len(work_order_ids),
"completed": 0,
"overdue": 0,
"in_progress": 0,
"details": []
}
for wo_id in work_order_ids:
wo = get_work_order_details(wo_id)
if wo:
status = check_work_order_status(wo_id)
if status['is_completed']:
report["completed"] += 1
elif status['is_overdue']:
report["overdue"] += 1
elif wo['status'] in ['in_progress', 'assigned']:
report["in_progress"] += 1
report["details"].append({
"id": wo_id,
"title": wo["title"],
"status": wo["status_display"],
"priority": wo["priority_display"],
"client": wo["client_name"],
"team": wo["assigned_team"]["name"] if wo["assigned_team"] else None,
"call_attempts": wo["call_attempts"],
"created_at": wo["created_at"]
})
return report
3. Customer Communication
Track customer contact history:
def get_customer_contact_summary(work_order_id):
"""Get summary of customer contact attempts."""
wo = get_work_order_details(work_order_id)
if not wo:
return None
call_summary = {}
for call in wo['call_logs']:
outcome = call['outcome']
call_summary[outcome] = call_summary.get(outcome, 0) + 1
return {
"total_attempts": wo["call_attempts"],
"call_breakdown": call_summary,
"last_contact": wo['call_logs'][-1] if wo['call_logs'] else None,
"customer_phone": wo["client_contact"]
}
Best Practices
1. Cache Results
Cache work order details to reduce API calls:
import time
from functools import lru_cache
@lru_cache(maxsize=100)
def cached_get_work_order(work_order_id, ttl_hash=None):
"""Get work order with caching (TTL via hash)."""
return get_work_order_details(work_order_id)
def get_ttl_hash(seconds=300):
"""Return the same value within `seconds` time period."""
return round(time.time() / seconds)
# Usage with 5-minute cache
work_order = cached_get_work_order(
"550e8400-e29b-41d4-a716-446655440000",
ttl_hash=get_ttl_hash(300)
)
2. Error Handling
Implement robust error handling:
def safe_get_work_order(work_order_id, max_retries=3):
"""Get work order with retry logic and error handling."""
for attempt in range(max_retries):
try:
response = requests.get(
f"{BASE_URL}/workorders/{work_order_id}/",
headers=headers,
timeout=30
)
if response.status_code == 200:
return response.json()
elif response.status_code == 404:
return None # Work order doesn't exist
else:
print(f"Attempt {attempt + 1} failed: {response.status_code}")
if attempt == max_retries - 1:
raise Exception("Max retries exceeded")
time.sleep(2 ** attempt)
except requests.RequestException as e:
print(f"Network error on attempt {attempt + 1}: {e}")
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
return None
3. Bulk Operations
Efficiently process multiple work orders:
import concurrent.futures
from typing import List, Dict
def get_multiple_work_orders(work_order_ids: List[str], max_workers=5) -> Dict[str, dict]:
"""Get multiple work orders concurrently."""
results = {}
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
# Submit all requests
future_to_id = {
executor.submit(get_work_order_details, wo_id): wo_id
for wo_id in work_order_ids
}
# Collect results
for future in concurrent.futures.as_completed(future_to_id):
wo_id = future_to_id[future]
try:
result = future.result()
results[wo_id] = result
except Exception as e:
print(f"Error getting work order {wo_id}: {e}")
results[wo_id] = None
return results
Next Steps
- List Work Orders → Query and filter work orders
- Create Work Order → Programmatically create work orders
- Code Examples → Comprehensive integration examples