Skip to main content

Create Work Order

Create a new work order in the Centro Access system.

Endpoint

POST /api/v1/external/workorders/

Headers

HeaderValueRequired
AuthorizationApi-Key YOUR_API_KEYYes
Content-Typeapplication/jsonYes

Request Body

The create work order endpoint accepts only the essential fields that are actually used when creating new work orders. The title is automatically generated from the client name and service category.

Required Fields

FieldTypeDescription
client_namestringName of the client (max 255 characters)
client_contactstringClient's phone number in international format

Optional Fields

FieldTypeDefaultDescription
service_categorystring"installation"Type of service work
prioritystring"medium"Priority level of the work order
additional_informationstring""Additional notes or instructions (max 1000 characters)
preferred_timestringnullISO 8601 datetime when client prefers service
due_datestringnullISO 8601 date when work should be completed
latitudenumbernullGPS latitude coordinate (-90 to 90)
longitudenumbernullGPS longitude coordinate (-180 to 180)

Field Values

service_category Options

  • "installation" - Fiber installation work
  • "mdu" - Multi-dwelling unit work
  • "extension" - Service extension work
  • "transmission" - Transmission line work
  • "construction" - Construction projects
  • "support" - Support and maintenance

priority Options

  • "low" - Low priority
  • "medium" - Medium priority (default)
  • "high" - High priority
  • "urgent" - Urgent priority

Automatic Field Generation

When creating a work order, certain fields are automatically set:

  • title: Generated as "{client_name} - {Service Category}" (e.g., "John Doe - Installation")
  • status: Always set to "dispatch" for new work orders
  • organisation: Set from the API key context
  • created_by: Set to the system user associated with the API key

Request Example

Minimal Request

{
"client_name": "John Doe",
"client_contact": "+256701234567"
}

Complete Request

{
"client_name": "Jane Smith",
"client_contact": "+256707654321",
"service_category": "installation",
"priority": "high",
"additional_information": "Customer prefers morning appointments between 8-11 AM. Gate code is 1234.",
"preferred_time": "2025-10-25T09:00:00Z",
"due_date": "2025-10-30",
"latitude": 0.3163,
"longitude": 32.5822
}

Response

Success Response (201 Created)

{
"success": true,
"message": "Work order created successfully",
"work_order": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Jane Smith - Installation",
"client_name": "Jane Smith",
"client_contact": "+256707654321",
"additional_information": "Customer prefers morning appointments between 8-11 AM. Gate code is 1234.",
"preferred_time": "2025-10-25T09:00:00Z",
"due_date": "2025-10-30",
"status": "dispatch",
"status_display": "Dispatch",
"priority": "high",
"priority_display": "High",
"service_category": "installation",
"service_category_display": "Installation",
"latitude": 0.3163,
"longitude": 32.5822,
"assigned_team": null,
"assigned_team_details": null,
"service_zone": null,
"service_zone_details": null,
"organisation": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Centro Access Uganda"
},
"created_at": "2025-10-24T14:30:00Z",
"updated_at": "2025-10-24T14:30:00Z",
"created_by_details": {
"id": "987fcdeb-51a2-43d1-9c12-345678901234",
"username": "api_system_user",
"first_name": "API",
"last_name": "System"
},
"call_attempts": 0,
"last_status_change": "2025-10-24T14:30:00Z",
"is_deleted": false,
"work_order_call_logs": []
}
}

Error Responses

400 Bad Request - Validation Error

{
"error": "Invalid data provided",
"details": {
"client_name": ["This field is required."],
"client_contact": ["This field is required."]
}
}

400 Bad Request - Invalid Phone Number

{
"error": "Invalid data provided",
"details": {
"client_contact": ["Enter a valid phone number (e.g. +256701234567)."]
}
}

400 Bad Request - Invalid Coordinates

{
"error": "Invalid data provided",
"details": {
"latitude": ["Ensure this value is greater than or equal to -90."],
"longitude": ["Ensure this value is less than or equal to 180."]
}
}

401 Unauthorized

{
"error": "Authentication credentials were not provided."
}

403 Forbidden - Missing Permission

{
"error": "You do not have permission to perform this action.",
"required_permission": "workorder.add_workorder"
}

Code Examples

Python

import requests

# Create work order
url = "https://app.centroaccess.com/api/v1/external/workorders/"
headers = {
"Authorization": "Api-Key your-api-key-here",
"Content-Type": "application/json"
}

data = {
"client_name": "Alice Johnson",
"client_contact": "+256701234567",
"service_category": "installation",
"priority": "high",
"additional_information": "Customer has requested morning installation",
"preferred_time": "2025-10-25T09:00:00Z",
"latitude": 0.3163,
"longitude": 32.5822
}

response = requests.post(url, json=data, headers=headers)

if response.status_code == 201:
work_order = response.json()["work_order"]
print(f"Created work order: {work_order['id']}")
print(f"Title: {work_order['title']}")
print(f"Status: {work_order['status_display']}")
else:
print(f"Error: {response.json()}")

JavaScript

// Create work order
const createWorkOrder = async () => {
const response = await fetch('https://app.centroaccess.com/api/v1/external/workorders/', {
method: 'POST',
headers: {
'Authorization': 'Api-Key your-api-key-here',
'Content-Type': 'application/json',
},
body: JSON.stringify({
client_name: 'Bob Wilson',
client_contact: '+256707654321',
service_category: 'mdu',
priority: 'medium',
additional_information: 'Building access requires security clearance',
due_date: '2025-11-01'
})
});

if (response.ok) {
const result = await response.json();
console.log('Created work order:', result.work_order.id);
console.log('Title:', result.work_order.title);
return result.work_order;
} else {
const error = await response.json();
console.error('Error creating work order:', error);
throw new Error(error.error);
}
};

cURL

# Minimal work order creation
curl -X POST "https://app.centroaccess.com/api/v1/external/workorders/" \
-H "Authorization: Api-Key your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"client_name": "Sarah Connor",
"client_contact": "+256701234567"
}'

# Complete work order creation
curl -X POST "https://app.centroaccess.com/api/v1/external/workorders/" \
-H "Authorization: Api-Key your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"client_name": "Michael Davis",
"client_contact": "+256707654321",
"service_category": "extension",
"priority": "urgent",
"additional_information": "Emergency service required",
"preferred_time": "2025-10-24T16:00:00Z",
"due_date": "2025-10-25",
"latitude": 0.3476,
"longitude": 32.5825
}'

Validation Rules

Client Name

  • Required: Yes
  • Type: String
  • Max Length: 255 characters
  • Rules: Cannot be empty or contain only whitespace

Client Contact

  • Required: Yes
  • Type: Phone number
  • Format: International format with country code (e.g., +256701234567)
  • Rules: Must be a valid phone number

Service Category

  • Required: No (defaults to "installation")
  • Type: String
  • Options: installation, mdu, extension, transmission, construction, support

Priority

  • Required: No (defaults to "medium")
  • Type: String
  • Options: low, medium, high, urgent

Additional Information

  • Required: No
  • Type: String
  • Max Length: 1000 characters

Preferred Time

  • Required: No
  • Type: ISO 8601 datetime string
  • Format: YYYY-MM-DDTHH:MM:SSZ

Due Date

  • Required: No
  • Type: ISO 8601 date string
  • Format: YYYY-MM-DD

Coordinates

  • Required: No
  • Latitude: Number between -90 and 90
  • Longitude: Number between -180 and 180

Best Practices

1. Always Provide Client Information

{
"client_name": "Clear, full name",
"client_contact": "+256701234567"
}

2. Use Appropriate Service Categories

Choose the service category that best matches the work type:

  • Use "installation" for new fiber connections
  • Use "mdu" for multi-dwelling unit projects
  • Use "support" for maintenance and troubleshooting

3. Set Realistic Priorities

  • Use "urgent" sparingly for true emergencies
  • Most work orders should be "medium" priority
  • Use "high" for time-sensitive but non-emergency work

4. Include Location Data When Available

{
"latitude": 0.3163,
"longitude": 32.5822,
"additional_information": "Near Kampala Central Business District"
}

5. Provide Clear Additional Information

{
"additional_information": "Customer available weekday mornings. Security code: 1234. Contact property manager if needed: +256701111111"
}

6. Use Proper Time Formats

{
"preferred_time": "2025-10-25T09:00:00Z",
"due_date": "2025-10-30"
}

Success Response (201 Created)

{
"success": true,
"message": "Work order created successfully",
"work_order": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"title": "Install fiber connection",
"client_name": "John Doe",
"client_contact": "+1234567890",
"additional_information": "Customer prefers morning appointments",
"status": "dispatch",
"status_display": "Dispatch",
"priority": "high",
"priority_display": "High",
"service_category": "installation",
"service_category_display": "Installation",
"due_date": "2025-12-31",
"preferred_time": "2025-10-25T10:00:00Z",
"longitude": -73.935242,
"latitude": 40.730610,
"created_at": "2025-10-23T14:30:00Z",
"updated_at": "2025-10-23T14:30:00Z",
"created_by": {
"id": "880e8400-e29b-41d4-a716-446655440003",
"email": "api-key-system@centroaccess.com",
"name": "API Key: Integration System"
},
"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"
}
}
}

Work Order Object Fields

FieldTypeDescription
idUUIDUnique work order identifier
titlestringWork order title
client_namestringCustomer/client name
client_contactstringClient phone number
additional_informationstringAdditional notes
statusstringCurrent status (always "dispatch" for new orders)
status_displaystringHuman-readable status
prioritystringPriority level code
priority_displaystringHuman-readable priority
service_categorystringService category code
service_category_displaystringHuman-readable category
due_datestring/nullDue date (YYYY-MM-DD)
preferred_timestring/nullPreferred time (ISO format)
longitudefloat/nullLongitude coordinate
latitudefloat/nullLatitude coordinate
created_atstringCreation timestamp
updated_atstringLast update timestamp
created_byobjectSystem user information
service_zoneobject/nullService zone details
assigned_teamobject/nullAssigned team details

Examples

Basic Work Order

Create a simple work order with only required fields:

curl -X POST "https://app.centroaccess.com/api/v1/external/workorders/" \
-H "Authorization: Api-Key your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"title": "Install fiber connection",
"client_contact": "+1234567890"
}'

Complete Work Order

Create a work order with all optional fields:

curl -X POST "https://app.centroaccess.com/api/v1/external/workorders/" \
-H "Authorization: Api-Key your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"title": "Complete fiber installation",
"client_name": "John Doe",
"client_contact": "+1234567890",
"additional_information": "Customer prefers morning appointments. Gate code: 1234",
"priority": "high",
"service_category": "installation",
"service_zone": "660e8400-e29b-41d4-a716-446655440001",
"assigned_team": "770e8400-e29b-41d4-a716-446655440002",
"due_date": "2025-12-31",
"preferred_time": "2025-10-25T10:00:00Z",
"longitude": -73.935242,
"latitude": 40.730610
}'

High Priority Work Order

Create an urgent work order:

curl -X POST "https://app.centroaccess.com/api/v1/external/workorders/" \
-H "Authorization: Api-Key your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"title": "Emergency fiber repair",
"client_name": "Business Customer",
"client_contact": "+1234567890",
"additional_information": "Business down, requires immediate attention",
"priority": "urgent",
"service_category": "support"
}'

Survey Work Order

Create a survey work order with location:

curl -X POST "https://app.centroaccess.com/api/v1/external/workorders/" \
-H "Authorization: Api-Key your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"title": "Site survey for new installation",
"client_name": "New Customer",
"client_contact": "+1234567890",
"additional_information": "Survey required before installation can proceed",
"priority": "medium",
"service_category": "survey",
"longitude": -73.935242,
"latitude": 40.730610
}'

Service Categories

Available service category values:

CategoryDescription
surveySurvey work
installationInstallation work
mduMulti-dwelling unit work
service_providerService provider work
extensionExtension work
transmissionTransmission work
constructionConstruction work
reviewReview work
supportSupport work
relocationRelocation work
equipment_recoveryEquipment recovery

Priority Levels

Available priority values:

PriorityDescriptionUse Case
lowLow priorityNon-urgent maintenance
mediumMedium priority (default)Standard work orders
highHigh priorityImportant customer requests
urgentUrgent priorityEmergency repairs, business down

Error Responses

Validation Error

Status Code: 400 Bad Request

{
"error": "Invalid data provided",
"details": {
"client_contact": ["This field is required."],
"priority": ["'invalid' is not a valid choice."],
"due_date": ["Date has wrong format. Use one of these formats instead: YYYY-MM-DD."]
}
}

Invalid Service Zone

Status Code: 400 Bad Request

{
"error": "Invalid data provided",
"details": {
"service_zone": ["Invalid pk \"invalid-uuid\" - object does not exist."]
}
}

Invalid Team

Status Code: 400 Bad Request

{
"error": "Invalid data provided",
"details": {
"assigned_team": ["Invalid pk \"invalid-uuid\" - object does not exist."]
}
}

Authentication Required

Status Code: 401 Unauthorized

{
"detail": "Invalid API key"
}

Insufficient Permissions

Status Code: 403 Forbidden

{
"error": "Insufficient permissions",
"required_permission": "workorder.add_workorder"
}

Server Error

Status Code: 500 Internal Server Error

{
"error": "Failed to create work order",
"details": "Unexpected error occurred"
}

Code Examples

Python

import requests
from datetime import datetime, timedelta

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 create_work_order(title, client_contact, **kwargs):
"""Create a new work order."""
data = {
"title": title,
"client_contact": client_contact,
**kwargs
}

response = requests.post(
f"{BASE_URL}/workorders/",
headers=headers,
json=data
)

if response.status_code == 201:
result = response.json()
work_order = result["work_order"]
print(f"✅ Created work order: {work_order['id']}")
print(f" Title: {work_order['title']}")
print(f" Status: {work_order['status_display']}")
print(f" Priority: {work_order['priority_display']}")
return work_order
else:
print(f"❌ Error: {response.status_code}")
print(f" Details: {response.json()}")
return None

def create_urgent_work_order(title, client_name, client_contact, details):
"""Create an urgent work order."""
return create_work_order(
title=title,
client_name=client_name,
client_contact=client_contact,
additional_information=details,
priority="urgent",
service_category="support"
)

def create_installation_order(title, client_name, client_contact,
service_zone_id=None, team_id=None,
due_date=None, coordinates=None):
"""Create an installation work order."""
kwargs = {
"client_name": client_name,
"priority": "medium",
"service_category": "installation"
}

if service_zone_id:
kwargs["service_zone"] = service_zone_id
if team_id:
kwargs["assigned_team"] = team_id
if due_date:
kwargs["due_date"] = due_date
if coordinates:
kwargs["latitude"] = coordinates["lat"]
kwargs["longitude"] = coordinates["lng"]

return create_work_order(title, client_contact, **kwargs)

# Usage examples
basic_order = create_work_order(
"Install fiber connection",
"+1234567890",
client_name="John Doe",
priority="high"
)

urgent_order = create_urgent_work_order(
"Emergency fiber repair",
"Business Customer",
"+1234567890",
"Business is down, requires immediate attention"
)

installation_order = create_installation_order(
"New residential installation",
"Jane Smith",
"+1234567890",
service_zone_id="660e8400-e29b-41d4-a716-446655440001",
due_date="2025-11-15",
coordinates={"lat": 40.730610, "lng": -73.935242}
)

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 createWorkOrder(workOrderData) {
try {
const response = await axios.post(
`${BASE_URL}/workorders/`,
workOrderData,
{ headers }
);

const { work_order } = response.data;
console.log(`✅ Created work order: ${work_order.id}`);
console.log(` Title: ${work_order.title}`);
console.log(` Status: ${work_order.status_display}`);
console.log(` Priority: ${work_order.priority_display}`);

return work_order;
} catch (error) {
console.error('❌ Error creating work order:');
if (error.response) {
console.error(` Status: ${error.response.status}`);
console.error(` Details:`, error.response.data);
} else {
console.error(` Error: ${error.message}`);
}
return null;
}
}

async function createUrgentWorkOrder(title, clientName, clientContact, details) {
return await createWorkOrder({
title,
client_name: clientName,
client_contact: clientContact,
additional_information: details,
priority: 'urgent',
service_category: 'support'
});
}

async function createInstallationOrder(options) {
const {
title,
clientName,
clientContact,
serviceZoneId,
teamId,
dueDate,
coordinates,
additionalInfo
} = options;

const workOrderData = {
title,
client_name: clientName,
client_contact: clientContact,
priority: 'medium',
service_category: 'installation'
};

if (serviceZoneId) workOrderData.service_zone = serviceZoneId;
if (teamId) workOrderData.assigned_team = teamId;
if (dueDate) workOrderData.due_date = dueDate;
if (coordinates) {
workOrderData.latitude = coordinates.lat;
workOrderData.longitude = coordinates.lng;
}
if (additionalInfo) workOrderData.additional_information = additionalInfo;

return await createWorkOrder(workOrderData);
}

// Usage examples
async function examples() {
// Basic work order
await createWorkOrder({
title: 'Install fiber connection',
client_contact: '+1234567890',
client_name: 'John Doe',
priority: 'high'
});

// Urgent work order
await createUrgentWorkOrder(
'Emergency fiber repair',
'Business Customer',
'+1234567890',
'Business is down, requires immediate attention'
);

// Installation work order
await createInstallationOrder({
title: 'New residential installation',
clientName: 'Jane Smith',
clientContact: '+1234567890',
serviceZoneId: '660e8400-e29b-41d4-a716-446655440001',
dueDate: '2025-11-15',
coordinates: { lat: 40.730610, lng: -73.935242 },
additionalInfo: 'Customer prefers afternoon appointments'
});
}

examples();

Validation Rules

Phone Number Format

Client contact should be in E.164 format:

# Good formats
"+1234567890"
"+12345678901"
"+44123456789"

# Acceptable but not recommended
"1234567890"
"(123) 456-7890"
"123-456-7890"

Title Length

Title must not exceed 255 characters:

# Good
"Install fiber connection for residential customer"

# Too long (over 255 characters)
"Very long title that exceeds the maximum allowed length for work order titles and will be rejected by the API validation because it contains too many characters and goes beyond the 255 character limit set in the database schema..."

Date Formats

Due date must be in YYYY-MM-DD format:

# Good
"2025-12-31"
"2025-01-15"

# Bad
"12/31/2025"
"31-12-2025"
"December 31, 2025"

Coordinate Validation

Coordinates must be valid latitude/longitude values:

# Good
"latitude": 40.730610, # Valid latitude (-90 to 90)
"longitude": -73.935242 # Valid longitude (-180 to 180)

# Bad
"latitude": 200, # Invalid (outside range)
"longitude": "invalid" # Invalid (not a number)

Best Practices

1. Validate Data Before Sending

def validate_work_order_data(data):
"""Validate work order data before sending to API."""
errors = []

if not data.get('title'):
errors.append("Title is required")
elif len(data['title']) > 255:
errors.append("Title must be 255 characters or less")

if not data.get('client_contact'):
errors.append("Client contact is required")

if 'priority' in data and data['priority'] not in ['low', 'medium', 'high', 'urgent']:
errors.append("Invalid priority value")

return errors

# Use validation before API call
data = {"title": "Install fiber", "client_contact": "+1234567890"}
errors = validate_work_order_data(data)
if errors:
print("Validation errors:", errors)
else:
create_work_order(**data)

2. Handle Errors Gracefully

def safe_create_work_order(data, max_retries=3):
"""Create work order with retry logic."""
for attempt in range(max_retries):
try:
response = requests.post(url, headers=headers, json=data)

if response.status_code == 201:
return response.json()
elif response.status_code == 400:
# Validation error - don't retry
print("Validation error:", response.json())
return None
else:
# Server error - retry
print(f"Attempt {attempt + 1} failed: {response.status_code}")
if attempt == max_retries - 1:
raise Exception("Max retries exceeded")
time.sleep(2 ** attempt) # Exponential backoff

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. Use Batch Creation for Multiple Orders

def create_multiple_work_orders(work_orders):
"""Create multiple work orders with proper error handling."""
results = []

for i, wo_data in enumerate(work_orders):
print(f"Creating work order {i + 1}/{len(work_orders)}")

try:
result = create_work_order(**wo_data)
results.append({"success": True, "data": result})
except Exception as e:
results.append({"success": False, "error": str(e), "data": wo_data})

# Rate limiting: small delay between requests
time.sleep(0.1)

# Summary
successful = sum(1 for r in results if r["success"])
print(f"Created {successful}/{len(work_orders)} work orders successfully")

return results

Next Steps