> ## Documentation Index
> Fetch the complete documentation index at: https://developers.kardinal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Field services

> Field-service example: skill preference on demanding jobs, opportunistic scheduling of backlog jobs, a travel-distance cap, and technicians who start from home.

A field-service operation dispatches technicians directly from home rather than a shared depot, matches or prefers specific certifications to specific jobs, keeps drive time between two appointments short, and often has a backlog of lower-priority jobs that only get slotted in when the schedule has room.

## What makes this vertical distinctive

* **Skill preference** — a senior technician is preferred on demanding jobs, without excluding a generalist when the senior isn't available.
* **Opportunistic scheduling** — lower-priority jobs stay optional and only get planned when the route has capacity left.
* **Travel-distance cap between jobs** — a technician's hops from one job to the next stay under a set distance.
* **Home start/end** — every route starts and ends at the technician's own home, not a shared depot.

## Combined example

```json theme={null}
{
  "resources": [
    {
      "id": "technician-senior",
      "vehicleProfile": { "type": "car" },
      "departure": { "lon": 2.375, "lat": 48.872 },
      "arrival": { "lon": 2.375, "lat": 48.872 },
      "preferredStopTags": ["tag:senior-preferred"],
      "maxInterStopDistanceInKm": { "firstTravel": 100, "interStop": 15, "lastTravel": 100 }
    },
    {
      "id": "technician-junior",
      "vehicleProfile": { "type": "car" },
      "departure": { "lon": 2.362, "lat": 48.824 },
      "arrival": { "lon": 2.362, "lat": 48.824 }
    }
  ],
  "orders": [
    {
      "id": "order-demanding-client",
      "stops": [
        {
          "type": "single",
          "id": "stop-demanding-client",
          "position": { "lon": 2.38, "lat": 48.832 },
          "kind": "delivery",
          "operationDuration": "PT45M",
          "tags": ["tag:senior-preferred"]
        }
      ]
    },
    {
      "id": "order-routine-job",
      "stops": [
        {
          "type": "single",
          "id": "stop-routine-job",
          "position": { "lon": 2.358, "lat": 48.836 },
          "kind": "delivery",
          "operationDuration": "PT20M"
        }
      ],
      "priority": 5,
      "optional": true
    }
  ],
  "objectives": ["maximizeMandatoryStops", "minimizeResources", "maximizePreferredStops", "maximizeOptionalStops", "minimizeDistance"]
}
```

### Skill preference

`technician-senior.preferredStopTags: ["tag:senior-preferred"]` is matched against the same tag on `stop-demanding-client`. See [Driver skills and qualifications](/guides/advanced-constraints#driver-skills-and-qualifications) — the exact worked example this pattern follows.

### Opportunistic scheduling

`order-routine-job` sets `optional: true` with a positive `priority` (lower numbers matter more, so `5` ranks it below the default `0`), so the engine only plans it once every mandatory and preferred stop is already placed, via the `maximizeOptionalStops` objective. A higher `priority` number pushes a job further down the queue relative to other optional orders. See [Soft constraints](/concepts/hard-vs-soft-constraints#soft-constraints).

### Travel-distance cap between jobs

`technician-senior.maxInterStopDistanceInKm` bounds each leg of the tour independently: `firstTravel`/`lastTravel` (home to first job, last job to home) get a looser cap than `interStop` (job to job), keeping consecutive appointments close together without also restricting how far the day's first and last jobs can be from home.

### Home start/end

Each technician's `departure`/`arrival` points to its own position rather than a shared depot — `technician-senior` and `technician-junior` don't share coordinates. See [Depot vs. position](/reference/data-model#depot-vs-position) for how a "depot" is just a resource's `departure`/`arrival`, not a first-class object.

## Full payload

> **Full payload — ready to submit as POST /plans**
>
> The preceding example isolates the four mechanisms this vertical needs; this expands it to the scale of a real working day — a full fleet schedule (`workingTimeWindow`, `departure`, `arrival`), the complete `objectives` list, and enough jobs to look like an actual route rather than a minimal illustration. Submit it as-is via [`POST /plans`](/api-reference/plan/create-a-plan) — the service assigns the plan's `id`, so don't include one of your own. Its datetimes are local times, read in the plan's `tz` (`Europe/Paris`); see [Dates and time zones](/reference/data-model#dates-and-time-zones).
>
> ```json theme={null}
> {
>   "tz": "Europe/Paris",
>   "resources": [
>     {
>       "id": "technician-senior",
>       "vehicleProfile": { "type": "car" },
>       "workingTimeWindow": { "begin": "2026-08-03 07:00", "end": "2026-08-03 17:00" },
>       "departure": { "lon": 2.375, "lat": 48.872 },
>       "arrival": { "lon": 2.375, "lat": 48.872 },
>       "skills": ["skill:electrical-certification", "skill:gas-certification"],
>       "preferredStopTags": ["tag:senior-preferred"],
>       "tags": ["technician:1"],
>       "maxInterStopDistanceInKm": { "firstTravel": 100, "interStop": 15, "lastTravel": 100 }
>     },
>     {
>       "id": "technician-junior",
>       "vehicleProfile": { "type": "car" },
>       "workingTimeWindow": { "begin": "2026-08-03 07:00", "end": "2026-08-03 17:00" },
>       "departure": { "lon": 2.362, "lat": 48.824 },
>       "arrival": { "lon": 2.362, "lat": 48.824 },
>       "tags": ["seniority:junior", "technician:2"]
>     }
>   ],
>   "orders": [
>     {
>       "id": "order-job-0",
>       "stops": [
>         { "type": "single", "id": "stop-job-0", "position": { "lon": 2.385, "lat": 48.86 }, "kind": "delivery", "operationDuration": "PT30M", "tags": ["job:standard"] }
>       ]
>     },
>     {
>       "id": "order-job-1",
>       "stops": [
>         { "type": "single", "id": "stop-job-1", "position": { "lon": 2.35, "lat": 48.858 }, "kind": "delivery", "operationDuration": "PT30M", "tags": ["job:standard"] }
>       ]
>     },
>     {
>       "id": "order-demanding-client",
>       "stops": [
>         {
>           "type": "single",
>           "id": "stop-demanding-client",
>           "position": { "lon": 2.38, "lat": 48.832 },
>           "kind": "delivery",
>           "operationDuration": "PT45M",
>           "tags": ["tag:senior-preferred"],
>           "preferredTimeWindows": [{ "begin": "2026-08-03 09:00", "end": "2026-08-03 11:00" }]
>         }
>       ]
>     },
>     {
>       "id": "order-routine-job",
>       "stops": [
>         {
>           "type": "single",
>           "id": "stop-routine-job",
>           "position": { "lon": 2.358, "lat": 48.836 },
>           "kind": "delivery",
>           "operationDuration": "PT20M",
>           "authorizedTimeWindows": [{ "begin": "2026-08-03 14:00", "end": "2026-08-03 16:00" }]
>         }
>       ],
>       "priority": 5,
>       "optional": true
>     },
>     {
>       "id": "order-restricted-site",
>       "stops": [
>         { "type": "single", "id": "stop-restricted-site", "position": { "lon": 2.395, "lat": 48.845 }, "kind": "delivery", "operationDuration": "PT30M", "tags": ["site:restricted-access"] }
>       ]
>     },
>     {
>       "id": "order-gas-installation",
>       "stops": [
>         { "type": "single", "id": "stop-gas-installation", "position": { "lon": 2.34, "lat": 48.865 }, "kind": "delivery", "operationDuration": "PT90M" }
>       ],
>       "requiredSkills": ["skill:gas-certification"]
>     }
>   ],
>   "objectives": ["maximizeMandatoryStops", "minimizeDelay", "minimizeResources", "maximizePreferredStops", "maximizeOptionalStops", "minimizeDistance", "minimizeWorkingDuration"],
>   "additionalConstraints": [
>     { "type": "forbiddenAssignment", "resourceTag": "technician:1", "stopTag": "site:restricted-access", "name": "technician-1-barred-from-site" }
>   ],
>   "additionalOperationDurations": [
>     { "resourceTag": "seniority:junior", "stopTag": "job:standard", "additionalOperationDuration": "PT15M" }
>   ]
> }
> ```

## See also

* [Modeling advanced constraints](/guides/advanced-constraints#driver-skills-and-qualifications) — `preferredStopTags` and `requiredSkills`, hard vs. soft.
* [Data model](/reference/data-model#depot-vs-position) — how per-resource `departure`/`arrival` represents a home or depot.
* [`orders` in the API reference](/api-reference/plan/create-a-plan#body-orders) — `optional`, `priority`, and the rest of the order/stop shape.

Ready to model an operation like this one? [Send your first API call](/getting-started/first-api-call) with your own data, or contact [customer.success@kardinal.ai](mailto:customer.success@kardinal.ai) to walk through your specific constraints.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.