Get Started in 7 Steps
Learn how to integrate PlanSolve's field service optimization using the REST API with PowerShell. This practical guide walks you through creating vehicles, visits, and solving optimization problems.
Create Vehicles
Define your technicians with shifts, skills, and starting locations
Code Example
{
"id": "tech1",
"homeLocation": [40.7128, -74.0060],
"skills": ["repair", "installation"],
"shifts": [{
"id": "morning",
"minStartTime": "2024-01-15T08:00:00",
"maxEndTime": "2024-01-15T17:00:00"
}]
}Explanation
Each vehicle represents a technician with their capabilities. The homeLocation is where they start and stop their day, skills is a flat list of attributes that will be used to match to visits requiring those skills, and shifts specify when the technician is available for work.
Create Visits
Define customer visits with time windows, required skills, and priorities
Code Example
{
"id": "visit1",
"name": "AC Repair - Downtown Office",
"location": [40.7589, -73.9851],
"timeWindows": [{
"minStartTime": "2024-01-15T09:00:00",
"maxEndTime": "2024-01-15T17:00:00"
}],
"serviceDuration": "PT60M",
"priority": "HIGH",
"requiredSkills": ["repair"]
}Explanation
Visits represent customer appointments. Time windows (optional) show when service can be performed, required skills (optional) ensure the right technician is assigned, and priority (optional) helps with scheduling order.
Create Request
Combine vehicles and visits into a complete optimization request
Code Example
{
"solver": "field_service",
"startDate": "2024-01-15",
"endDate": "2024-01-15",
"startDateTime": "2024-01-15T08:00:00",
"endDateTime": "2024-01-15T18:00:00",
"southwestCorner": [40.7000, -74.0200],
"northeastCorner": [40.8000, -73.9700],
"vehicles": [
{
"id": "tech1",
"homeLocation": [40.7128, -74.0060],
"skills": ["repair", "installation"],
"shifts": [{
"id": "morning",
"minStartTime": "2024-01-15T08:00:00",
"maxEndTime": "2024-01-15T17:00:00"
}]
}
],
"visits": [
{
"id": "visit1",
"name": "AC Repair - Downtown Office",
"location": [40.7589, -73.9851],
"timeWindows": [{
"minStartTime": "2024-01-15T09:00:00",
"maxEndTime": "2024-01-15T17:00:00"
}],
"serviceDuration": "PT60M",
"priority": "HIGH",
"requiredSkills": ["repair"]
}
]
}Explanation
This is your complete optimization request. The solver will find the best routes for your technicians to visit all customers while respecting constraints like skills matching, time windows, and shift availability. Use startDate/endDate to specify the planning range, and optionally use southwestCorner/northeastCorner to define a geographic bounding box that can help optimize the algorithm performance.
Create API Key
Generate an API key from your PlanSolve dashboard
Code Example
# Go to Settings > API Keys in your dashboard
# Click "Generate New API Key"
# Copy the generated key (e.g., "ps_live_abc123...")
# Store it securely in an environment variable
$env:PLANSOLVE_API_KEY="ps_live_abc123..."Explanation
API keys authenticate your requests and track usage. Never commit them to version control - use environment variables instead.
Prepare POST Request
Set up the PowerShell command with your data and API key
Code Example
# Save your request data to a file
$requestData = @{
solver = "field_service"
startDateTime = "2024-01-15T08:00:00"
endDateTime = "2024-01-15T18:00:00"
vehicles = @(...)
visits = @(...)
} | ConvertTo-Json -Depth 10
# Set up Invoke-RestMethod command
Invoke-RestMethod -Uri "https://plansolve.app/api/solve" \
-Method POST \
-Headers @{"Content-Type"="application/json"; "X-API-KEY"=$env:PLANSOLVE_API_KEY} \
-Body $requestDataExplanation
The POST request submits your optimization problem. The API immediately returns a job ID that you'll use to track progress.
Post and Poll Status
Submit the request and monitor progress until completion
Code Example
# Submit the request
$response = Invoke-RestMethod -Uri "https://plansolve.app/api/solve" \
-Method POST \
-Headers @{"Content-Type"="application/json"; "X-API-KEY"=$env:PLANSOLVE_API_KEY} \
-Body $requestData
# Extract job ID
$jobId = $response.jobId
Write-Host "Job ID: $jobId"
# Poll for status every 5 seconds
do {
$status = Invoke-RestMethod -Uri "https://plansolve.app/api/solve/$jobId" \
-Method GET \
-Headers @{"X-API-KEY"=$env:PLANSOLVE_API_KEY}
Write-Host "Status: $($status.status)"
if ($status.status -eq "COMPLETED") {
Write-Host "Optimization completed!"
break
} elseif ($status.status -eq "FAILED") {
Write-Host "Optimization failed!"
exit 1
}
Start-Sleep -Seconds 5
} while ($true)Explanation
Optimization is asynchronous and can take 30-60 seconds. Poll the status endpoint every 5 seconds until completion.
Process Results
Retrieve and use the optimized routes
Code Example
# Get the results
$results = Invoke-RestMethod -Uri "https://plansolve.app/api/solve/$jobId/result" \
-Method GET \
-Headers @{"X-API-KEY"=$env:PLANSOLVE_API_KEY}
# Display vehicle routes
Write-Host "Vehicle Routes:"
$results.vehicles | ForEach-Object {
Write-Host "Vehicle $($_.id): $($_.visits.Count) visits, total driving time: $($_.totalDrivingTimeSeconds)s"
}
# Display visit details with timing
Write-Host "Visit Details:"
$results.visits | ForEach-Object {
Write-Host " $($_.name): arrive $($_.arrivalTime), service $($_.startServiceTime), depart $($_.departureTime)"
}
# Show visit sequence for a specific vehicle
Write-Host "Visit Sequence for Vehicle 1@2024-01-15:"
$vehicle = $results.vehicles | Where-Object { $_.id -eq "1@2024-01-15" }
$vehicle.visits | ForEach-Object { Write-Host $_ }
# Save results to file
$results | ConvertTo-Json -Depth 10 | Out-File -FilePath "results.json" -Encoding UTF8Explanation
Results include two main sections: result.vehicles shows the visit order and driving times for each technician, while result.visits contains detailed timing information including arrival time, start service time, departure time, and driving time between visits. Use this data to update your dispatch system or mobile apps.
Complete Working Example
Here's a complete script you can run to test the entire workflow:
# Set your API key
$env:PLANSOLVE_API_KEY="your-api-key-here"
# Create request data
$requestData = @{
solver = "field_service"
startDate = "2024-01-15"
endDate = "2024-01-15"
startDateTime = "2024-01-15T08:00:00"
endDateTime = "2024-01-15T18:00:00"
southwestCorner = @(40.7000, -74.0200)
northeastCorner = @(40.8000, -73.9700)
vehicles = @(
@{
id = "tech1"
homeLocation = @(40.7128, -74.0060)
skills = @("repair", "installation")
shifts = @(
@{
id = "morning"
minStartTime = "2024-01-15T08:00:00"
maxEndTime = "2024-01-15T17:00:00"
}
)
}
)
visits = @(
@{
id = "visit1"
name = "AC Repair - Downtown Office"
location = @(40.7589, -73.9851)
timeWindows = @(
@{
minStartTime = "2024-01-15T09:00:00"
maxEndTime = "2024-01-15T17:00:00"
}
)
serviceDuration = "PT60M"
priority = "HIGH"
requiredSkills = @("repair")
}
)
} | ConvertTo-Json -Depth 10
# Submit request
Write-Host "Submitting optimization request..."
$response = Invoke-RestMethod -Uri "https://plansolve.app/api/solve" -Method POST -Headers @{"Content-Type"="application/json"; "X-API-KEY"=$env:PLANSOLVE_API_KEY} -Body $requestData
$jobId = $response.jobId
Write-Host "Job ID: $jobId"
# Poll status
Write-Host "Polling for completion..."
do {
$status = Invoke-RestMethod -Uri "https://plansolve.app/api/solve/$jobId" -Method GET -Headers @{"X-API-KEY"=$env:PLANSOLVE_API_KEY}
Write-Host "Status: $($status.status)"
if ($status.status -eq "COMPLETED") {
Write-Host "✅ Optimization completed!"
break
} elseif ($status.status -eq "FAILED") {
Write-Host "❌ Optimization failed!"
exit 1
}
Start-Sleep -Seconds 5
} while ($true)
# Get results
Write-Host "Retrieving results..."
$results = Invoke-RestMethod -Uri "https://plansolve.app/api/solve/$jobId/result" -Method GET -Headers @{"X-API-KEY"=$env:PLANSOLVE_API_KEY}
Write-Host "🎯 Final Routes:"
$results.vehicles | ForEach-Object {
Write-Host "Technician $($_.id): $($_.visits.Count) visits, total driving time: $($_.totalDrivingTimeSeconds)s"
}
Write-Host "📋 Visit Details:"
$results.visits | ForEach-Object {
Write-Host " - $($_.name) at $($_.arrivalTime)"
}
Write-Host "💾 Results saved to results.json"
$results | ConvertTo-Json -Depth 10 | Out-File -FilePath "results.json" -Encoding UTF8Understanding the Results
The API returns a structured response with two main sections: vehicles and visits. Here's what each contains:
Result Structure
{
"southWestCorner": [51.45, -0.15],
"northEastCorner": [51.55, -0.05],
"startDateTime": "2024-01-15T08:00:00",
"endDateTime": "2024-01-15T18:00:00",
"vehicles": [
{
"id": "1@2024-01-15",
"visits": ["1", "2", "3"],
"totalDrivingTimeSeconds": 5143,
"arrivalTime": "2024-01-15T15:59:38",
"departureTime": "2024-01-15T08:00:00"
}
],
"visits": [
{
"id": "1",
"name": "Task 1 - Day 1 Morning",
"vehicle": "1@2024-01-15",
"arrivalTime": "2024-01-15T08:16:11",
"startServiceTime": "2024-01-15T09:00:00",
"departureTime": "2024-01-15T09:30:00",
"drivingTimeSecondsFromPreviousStandstill": 971
}
]
}Vehicles Section
- visits - Array of visit IDs in execution order
- totalDrivingTimeSeconds - Total driving time for the day
- arrivalTime - When the vehicle returns home
- departureTime - When the vehicle leaves home
Visits Section
- arrivalTime - When technician arrives at location
- startServiceTime - When service actually begins
- departureTime - When technician leaves location
- drivingTimeSecondsFromPreviousStandstill - Travel time from previous stop
- vehicle - Which technician is assigned
Ready to Build?
Start with this example and gradually add more vehicles and visits as you become familiar with the API.
Need help? Check out our comprehensive documentation and examples.