Pinned Assignments

Why Does Pinned Assignments Matter?

Rout Optimizers are built to make cost-effective assignments across the fleet. However, sometimes when the business requires specific pairing between a task and a vehicle (eg: a contractual commitment to a client) leaving them to the optimizer's discretion is not acceptable. In such situations, operators rely on fragile workarounds (pre-assigning tasks, narrowing time windows etc) which can silently fail to honor real world constraints.

The Route Optimization API's Pinned Assignment feature provides a direct solution. By defining a relations.type: pinned, you can specify the tasks and the vehicle they must be assigned to. The optimizer then treats this as a non-negotiable assignment criteria: either the pinned tasks are assigned to the designated vehicle, or the entire optimization request fails.

Use Case: Field Service Technician-Task Pairing

A field service company dispatches two technicians from a shared depot in Los Angeles to handle six service jobs across the city. Each job involves an equipment pickup from a customer site. Two of the six jobs - Job 1 and Job 3 - requires a specialist certification that only Technician 2 holds. As a result, the operations team has a contractual obligation to ensure these jobs are handled by Technician 2. If Technician 2 cannot complete them due to any other reason, the operators need to know immediately so they can reschedule, and not discover the problem after the fact from a misleading route plan.

The dispatch team wants the optimizer to:

  • Guarantee Job 1 and Job 3 are assigned to Technician 2, without exception.
  • Assign the remaining four jobs (2, 4, 5, 6) freely across both technicians based on routing efficiency.
  • Fail the entire request immediately if Technician 2 cannot fulfil the pinned jobs.

Pinned Assignments feature delivers all three of these requirements simultaneously.

How Pinned Assignments work?

Pinned Assignments is a hard constraint which is configured by setting relations.type: pinned and specifying a relations.vehicle to complete the pinned relations.steps. It guarantees the assignment of pinned tasks. It is worth highlighting that non-pinned tasks in the same request are still assigned freely by the optimizer. The pinned relation constrains only the designated steps on the designated vehicle and everything else is optimised normally.

Following are some more rules that govern the feature:

  • Specifying the vehicle is mandatory: A pinned relation without a vehicle field is invalid and will return an error.
  • Steps cannot belong to multiple relations: A step included in a pinned relation cannot also appear in any other relations.type.
  • Pinning does not enforce sequence: Pinned steps are guaranteed to be assigned to the designated vehicle, but the optimizer decides the order in which they are served.
  • Cost and penalty overrides: The pin takes absolute precedence over all optimisation objectives and the optimizer cannot leave pinned steps unassigned.

Configuring the Feature: Input Parameters

Pinned Assignment is configured entirely within the top-level relations array of the request. The table below summarises all required fields:

ParameterType / LocationDescription
relations[].typestring (relation)Set to "pinned" to activate the Pinned Assignment type.
relations[].vehiclestring | integer (relation)The ID of the vehicle to which the steps must be assigned. Mandatory when type is "pinned".
relations[].stepsarray of objects (relation)The list of tasks to pin to the specified vehicle. Each step object contains a type ("job", "pickup", "delivery") and the corresponding task ID.

Example API Request & Response

Example API Request

The request below sets up two technicians, six pickup jobs, and a single pinned relation that locks Job 1 and Job 3 to Technician 2:

1
curl --location 'https://api.nextbillion.io/optimization/v2?key=<your_api_key>' \
2
--header 'Content-Type: application/json' \
3
--data '{
4
"description": "Pinned Assignment Example",
5
"locations": {
6
"id": 1,
7
"location": [
8
"34.06719484,-118.29932683", // index 0 – Shared depot
9
"34.05315973,-118.30890749", // index 1 – Job 1
10
"34.04580248,-118.28168441", // index 2 – Job 2
11
"34.04125227,-118.24920365", // index 3 – Job 3
12
"34.02450155,-118.30902433", // index 4 – Job 4
13
"34.06467837,-118.26602821", // index 5 – Job 5
14
"34.05190130,-118.27233743" // index 6 – Job 6
15
]
16
},
17
"jobs": [
18
{ "id": "Job 1", "location_index": 1, "service": 900, "pickup": [5] },
19
{ "id": "Job 2", "location_index": 2, "service": 1200, "pickup": [10] },
20
{ "id": "Job 3", "location_index": 3, "service": 600, "pickup": [5] },
21
{ "id": "Job 4", "location_index": 4, "service": 900, "pickup": [10] },
22
{ "id": "Job 5", "location_index": 5, "service": 600, "pickup": [5] },
23
{ "id": "Job 6", "location_index": 6, "service": 1500, "pickup": [5] }
24
],
25
"vehicles": [
26
{ "id": "Technician 1", "start_index": 0, "end_index": 0, "capacity": [20] },
27
{ "id": "Technician 2", "start_index": 0, "end_index": 0, "capacity": [20] }
28
],
29
"relations": [
30
{
31
"type": "pinned", // activates Pinned Relation
32
"vehicle": "Technician 2", // mandatory: target vehicle
33
"steps": [
34
{ "type": "job", "id": "Job 1" }, // pinned to Technician 2
35
{ "type": "job", "id": "Job 3" } // pinned to Technician 2
36
]
37
}
38
],
39
"options": { "routing": { "mode": "4w" } }
40
}'

Example API Response

The condensed response below shows routes for both technicians. All 6 jobs are assigned (unassigned: 0). Inline comments confirm which steps are pinned and which are freely assigned:

1
{
2
"description": "Pinned Assignment Example",
3
"result": {
4
"code": 0,
5
"summary": {
6
"cost": 4375, "routes": 2, "unassigned": 0,
7
"service": 5700, "duration": 4375, "distance": 31478
8
},
9
"routes": [
10
{
11
"vehicle": "Technician 1", "cost": 1766,
12
"steps": [
13
{ "type": "start", "location_index": 0, "load": [0], "distance": 0 },
14
{ "type": "job", "id": "Job 5", "load": [5], "distance": 3693 }, // freely assigned
15
{ "type": "job", "id": "Job 6", "load": [10], "distance": 5366 }, // freely assigned
16
{ "type": "job", "id": "Job 2", "load": [20], "distance": 6776 }, // freely assigned
17
{ "type": "end", "load": [20], "distance": 10856 }
18
],
19
"pickup": [20], "distance": 10856
20
},
21
{
22
"vehicle": "Technician 2", "cost": 2609,
23
"steps": [
24
{ "type": "start", "location_index": 0, "load": [0], "distance": 0 },
25
{ "type": "job", "id": "Job 1", "load": [5], "distance": 2710 }, // pinned
26
{ "type": "job", "id": "Job 4", "load": [15], "distance": 5953 }, // freely interleaved
27
{ "type": "job", "id": "Job 3", "load": [20], "distance": 13693 }, // pinned
28
{ "type": "end", "load": [20], "distance": 20622 }
29
],
30
"pickup": [20], "distance": 20622
31
}
32
]
33
},
34
"status": "Ok"
35
}

Interpreting the Output

To verify a pinned relation in the response, check the route for the designated vehicle and confirm that all pinned steps appear in its steps array. If the request succeeded, all pinned steps are guaranteed to be on the designated vehicle.

The table below shows the complete assignment across both technicians:

VehicleStopPinned?
Technician 1Job 5No
Technician 1Job 6No
Technician 1Job 2No
Technician 2Job 1✅ Yes
Technician 2Job 4No
Technician 2Job 3✅ Yes

Technician 1 Analysis

Route: Depot → Job 5 → Job 6 → Job 2 → End

  • All three jobs are freely assigned since there were no pinned constraint for Technician 1.
  • Neither Job 1 nor Job 3 appears on Technician 1's route, meaning the optimizer successfully prevents their assignment to the wrong vehicle.

Technician 2 Analysis

Route: Depot → Job 1 → Job 4 → Job 3 → End

  • Job 1 (pinned) appears as the first stop as part of guaranteed assignment for Technician 2.
  • Job 4 is a freely assigned job that the optimizer interleaved between the two pinned steps. Its placement between Job 1 and Job 3 is purely route-efficiency driven
  • Job 3 (pinned) appears as the third stop as part of guaranteed assignment for Technician 2.

What We Learned

This example illustrates several important takeaways about how Pinned Assignments behaves in practice:

  • Pinning guarantees assignment: This is the defining characteristic that separates a pinned assignment relation from other relation types. Use it when partial success is operationally unacceptable (contractual obligations, certified technician requirements etc).
  • Pinning controls vehicle assignment, not stop sequence: The optimizer remains free to determine when and in what order pinned steps are served on the designated vehicle. Job 4, an unpinned task, was interleaved between Job 1 and Job 3 on Technician 2's route.
  • Pinned vehicles can receive freely assigned tasks: Pinning a set of steps does not lock the vehicle to only those steps. The optimizer can assign non-pinned tasks if it is efficient to do so.

Explore other powerful features that the NextBillion.ai’s Route Optimization API can solve seamlessly.