Constraints
FG-API exposes constraints at several levels: per-job (time windows, skills, eligibility), per-resource (capacities, breaks, max driving time), and request-level (zones, relations, locks). This page surveys each type conceptually with short JSON snippets. For the exhaustive field list, see OptimizationRequest.
Time windows: hard vs soft
A TimeWindow is hard by default (must arrive in [start, end] or the job is dropped). Setting late_penalty and/or early_penalty converts the corresponding bound into a soft cost instead of a hard wall.
{ "start": 32400, "end": 34200, "late_penalty": 10 }
| early_penalty | late_penalty | Mode |
|---|---|---|
| null | null | Hard window |
| null | set | Soft upper bound (early still hard) |
| set | null | Soft lower bound (late still hard) |
| set | set | Fully soft (V-shaped cost curve) |
Capacities and exclusive dimensions
A resource's capacities can be a single integer (one default dimension) or a named dict for multiple cargo types tracked independently:
"capacities": { "weight_kg": 1000, "pallets": 12 }
exclusive_dimensions (request-level) marks dimensions that cannot be mixed in the same vehicle load at the same time — useful for incompatible cargo (e.g. food vs chemicals) that must never share a compartment simultaneously, even if total weight capacity would allow it.
Skills and proficiency
Jobs declare required_skills (and optionally a minimum skill_levels per skill); resources declare the skills/levels they have. A resource's skill_multipliers can additionally scale a job's service_time based on which skill is doing the work — e.g. a less proficient technician takes 1.5× as long on a job requiring "electrical":
"skill_multipliers": { "electrical": 1.5 }
Vehicle eligibility
allowed_resource_ids on a job restricts it to a named subset of resources, independent of skills — useful for contractual or operational constraints ("this customer only gets truck-1").
Zones
A zone restricts a set of locations to a set of resources:
{
"zones": [
{ "id": "zone-noord", "location_indices": [3, 4, 5], "allowed_resource_ids": ["truck-1"] }
]
}
Only truck-1 may serve locations 3, 4, and 5, regardless of what other jobs allow.
Relations
relations express dependencies between jobs:
| Type | Behavior |
|---|---|
precedence | The second job must start at least lapse seconds after the first. They may be on different vehicles. |
sequence | All listed jobs must be on the same vehicle, visited in exactly that order, with no other jobs interleaved. |
same_route | The listed jobs must be assigned to the same vehicle (order is free). |
different_route | The listed jobs must be assigned to different vehicles. |
{ "type": "precedence", "job_ids": ["job-3301", "job-3302"], "lapse": 1800 }
Breaks: explicit vs auto-generated
A resource can declare explicit breaks (a list of BreakSpec, each with id, time_window, duration):
"breaks": [{ "id": "lunch", "time_window": { "start": 41400, "end": 45000 }, "duration": 1800 }]
Or breaks can be auto-generated from driving/working limits: max_continuous_driving triggers a driving_break_duration (default 15s placeholder unit, typically configured in seconds matching your time unit) once continuous driving time is exceeded; max_continuous_work similarly triggers a work_break_duration (default 30) once continuous on-duty time is exceeded. Use explicit breaks when timing is regulated or contractual; use the auto limits when you just want legal driving-hour compliance without specifying exact break times.
Per-resource limits
| Field | Limits |
|---|---|
max_tasks | Maximum number of jobs/stops the resource may serve in a day. |
max_distance | Maximum total distance the resource may travel in a day. |
max_travel_time | Maximum total travel (driving) time in a day. |
Dump stations
A dump_station is a node a vehicle can detour to in order to reset one or more capacity dimensions mid-route:
{
"dump_stations": [
{ "id": "dump-1", "location_index": 9, "service_time": 900, "resets_capacities": ["waste"], "max_vehicles": 2 }
]
}
resets_capacities lists which dimensions get zeroed on a visit (other dimensions, e.g. recyclables, are unaffected). max_vehicles lets the solver model multiple vehicles dumping "in parallel" at the same physical station by spinning up virtual capacity-limited copies of the dump node, instead of forcing every truck through a single bottleneck slot.
Locks (for replanning)
locks let you freeze part of an existing solution before re-solving — used by /optimize/reoptimize and /optimize/replan. It typically includes a routes section pinning specific stop sequences and a disabled_resource_ids list for vehicles that should not receive any new work (e.g. already out of service for the day).
- OptimizationRequest schema — every field, exhaustively documented.
- Best Practices — practical guidance on tuning these constraints.