Skip to main content

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

ParameterTypeRequiredDescription
idUUIDYesUnique 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

FieldTypeDescription
idUUIDUnique work order identifier
titlestringWork order title
client_namestringCustomer/client name
client_contactstringClient phone number
additional_informationstringAdditional notes and information
statusstringCurrent status code
status_displaystringHuman-readable status
prioritystringPriority level code
priority_displaystringHuman-readable priority
service_categorystringService category code
service_category_displaystringHuman-readable category
queue_typestringQueue classification
due_datestring/nullDue date (YYYY-MM-DD)
preferred_timestring/nullPreferred appointment time (ISO format)
nicenessintegerPriority adjustment value
call_attemptsintegerNumber of customer contact attempts
last_status_changestringTimestamp of last status change
completed_atstring/nullCompletion timestamp
longitudefloat/nullLongitude coordinate
latitudefloat/nullLatitude coordinate
created_atstringCreation timestamp
updated_atstringLast update timestamp
is_overduebooleanWhether the work order is overdue
assigned_atstring/nullTeam assignment timestamp
FieldTypeDescription
service_zoneobject/nullService zone information
assigned_teamobject/nullAssigned team details
created_byobjectUser who created the work order
call_logsarrayCustomer contact history
inspectionsarrayRelated inspection records
child_work_ordersarrayRelated child work orders
next_possible_statusarrayAvailable 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:

FieldTypeDescription
idintegerUnique call log identifier
call_timestringTimestamp of the call
notesstringNotes about the call
outcomestringCall outcome (successful, no_answer, rescheduled, etc.)

Call Outcome Values

OutcomeDescription
successfulCall was successful
no_answerNo answer from customer
voicemailLeft voicemail
busyLine was busy
rescheduledAppointment rescheduled
cancelledCustomer cancelled
wrong_numberWrong phone number

Inspections

Inspection records show related quality checks:

FieldTypeDescription
idUUIDUnique inspection identifier
inspection_typestringType of inspection
statusstringInspection status
completed_atstring/nullCompletion timestamp
notesstringInspection notes

Inspection Types

TypeDescription
pre_installationPre-installation survey
post_installationPost-installation quality check
maintenanceRoutine maintenance inspection
troubleshootingProblem investigation

Inspection Status Values

StatusDescription
pendingNot yet started
in_progressCurrently being performed
completedSuccessfully completed
failedFailed inspection
cancelledCancelled 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