
Timefold Solve
CertifiedSubmit an optimization problem to the Timefold Platform
Timefold Solve
Submit an optimization problem to the Timefold Platform
Submits a modelInput dataset to a Timefold Platform model (Field Service Routing or Employee Scheduling).
When wait is false (the default) the task performs a single POST and immediately returns the jobId. Use the job id in a subsequent GetDataset task to poll for status or retrieve the solution.
When wait is true the task submits the dataset and polls the platform until solving completes (or requestTimeout elapses), then returns the jobId, solverStatus, score, and the full modelOutput. See the Timefold API documentation.
type: io.kestra.plugin.timefold.SolveExamples
Submit a Field Service Routing problem and capture the job ID for downstream tasks.
id: timefold_route
namespace: company.team
tasks:
- id: solve
type: io.kestra.plugin.timefold.Solve
apiKey: "{{ secret('TIMEFOLD_API_KEY') }}"
model: FIELD_SERVICE_ROUTING
solveDuration: PT30S
modelInput:
vehicles:
- id: Ann
shifts:
- id: Ann-2027-02-01
startLocation: [33.68786, -84.18487]
minStartTime: "2027-02-01T09:00:00Z"
visits:
- id: Visit A
location: [33.77301, -84.43838]
serviceDuration: PT1H30M
- id: log_job_id
type: io.kestra.plugin.core.log.Log
message: "Submitted job: {{ outputs.solve.jobId }}"
Build an Employee Scheduling dataset from CSV inputs and solve.
id: timefold_schedule
namespace: company.team
# employees.csv (name becomes the employee id):
# name,skills
# Alice,nursing|doctor
# Bob,nursing
#
# shifts.csv (required_skill becomes a requiredSkills object array):
# id,start,end,required_skill
# SHIFT-001,2027-02-01T08:00:00Z,2027-02-01T16:00:00Z,nursing
# SHIFT-002,2027-02-01T16:00:00Z,2027-02-02T00:00:00Z,nursing
inputs:
- id: employees_csv
type: FILE
- id: shifts_csv
type: FILE
tasks:
- id: build_dataset
type: io.kestra.plugin.scripts.python.Script
inputFiles:
employees.csv: "{{ inputs.employees_csv }}"
shifts.csv: "{{ inputs.shifts_csv }}"
script: |
import csv
from kestra import Kestra
employees = []
with open("employees.csv") as f:
for row in csv.DictReader(f):
employees.append({
"id": row["name"],
"skills": [{"id": s} for s in row["skills"].split("|")],
})
shifts = []
with open("shifts.csv") as f:
for row in csv.DictReader(f):
shifts.append({
"id": row["id"],
"start": row["start"],
"end": row["end"],
"requiredSkills": [row["required_skill"]],
})
Kestra.outputs({"modelInput": {"employees": employees, "shifts": shifts}})
- id: solve
type: io.kestra.plugin.timefold.Solve
apiKey: "{{ secret('TIMEFOLD_API_KEY') }}"
model: EMPLOYEE_SCHEDULING
solveDuration: PT1M
modelInput: "{{ outputs.build_dataset.vars.modelInput }}"
Submit a Field Service Routing problem and wait for the optimized solution.
id: timefold_route_wait
namespace: company.team
tasks:
- id: solve
type: io.kestra.plugin.timefold.Solve
apiKey: "{{ secret('TIMEFOLD_API_KEY') }}"
model: FIELD_SERVICE_ROUTING
solveDuration: PT30S
wait: true
modelInput:
vehicles:
- id: Ann
shifts:
- id: Ann-2027-02-01
startLocation: [33.68786, -84.18487]
minStartTime: "2027-02-01T09:00:00Z"
visits:
- id: Visit A
location: [33.77301, -84.43838]
serviceDuration: PT1H30M
- id: log_result
type: io.kestra.plugin.core.log.Log
message: "Solved {{ outputs.solve.jobId }} — status: {{ outputs.solve.solverStatus }}, score: {{ outputs.solve.score }}"
Properties
apiKey *Requiredstring
The Timefold Platform API key
Sent as the X-API-KEY header on every request. Provide it via a secret, for example apiKey: "{{ secret('TIMEFOLD_API_KEY') }}". The key must have access to the selected model.
model *Requiredstring
FIELD_SERVICE_ROUTINGEMPLOYEE_SCHEDULINGPICKUP_DELIVERY_ROUTINGThe Timefold model to solve with
Determines the REST resource the dataset is submitted to. FIELD_SERVICE_ROUTING uses the route-plans endpoint and EMPLOYEE_SCHEDULING uses the schedules endpoint.
modelInput *RequiredNon-dynamicobject
The optimization input dataset (modelInput)
The data to be optimized, following the selected model's schema. For Field Service Routing this contains vehicles and visits; for Employee Scheduling it contains employees, shifts, etc. Accepts a map, or a JSON string / expression that resolves to the modelInput object. The value is wrapped into the { "modelInput": ... } request body sent to Timefold.
baseUrl string
https://app.timefold.aiBase URL of the Timefold Platform API
Defaults to the Timefold managed cloud. Override this when running a self-hosted Timefold deployment. The model and resource path segments are appended automatically, so provide only the host, e.g. https://app.timefold.ai.
fetchType string
STORESTOREFETCHFETCH_ONENONEHow to return the modelOutput
Only applies when wait is true.
STORE(default): writesmodelOutputas a JSON file to Kestra's internal storage and returns its URI inuri. Recommended for large solutions.FETCH/FETCH_ONE: returnsmodelOutputinline in themodelOutputoutput field.NONE: discardsmodelOutputentirely (useful when onlysolverStatusandscoreare needed).
pluginDefaultsRef Non-dynamicstring
Reference (ref) of the pluginDefaults to apply to this task.
pollInterval string
PT2SHow often to poll the Timefold Platform for the solver status
Only applies when wait is true. Minimum is PT0.5S (500 ms). Defaults to PT2S (every 2 seconds).
requestTimeout string
PT10MOverall timeout for the whole operation, including queueing on the platform
Only applies when wait is true. If the solver has not completed within this duration the task fails. Should comfortably exceed solveDuration. Defaults to PT10M (10 minutes).
runName string
Optional run name attached to the submitted dataset
Stored as config.run.name and shown in the Timefold Platform UI.
solveDuration string
Maximum time Timefold should spend solving
Passed as the config.run.termination.spentLimit of the submitted dataset. Controls how long the platform solver runs; it does not affect when this task returns. When omitted, the Timefold Platform uses its built-in diminishing-returns termination to decide how long to run based on solution quality improvements over time.
wait booleanstring
falseWhether to poll for the solution before returning
When true the task polls the platform until solving completes (or requestTimeout elapses) and returns the full modelOutput, solverStatus, and score. When false (the default) the task submits the dataset and returns the jobId immediately.
Outputs
jobId string
The identifier of the solving job on the Timefold Platform
Pass this to a subsequent task to poll for status or retrieve the solution via the Timefold API.
modelOutput object
The optimized solution (modelOutput) returned inline (populated when fetchType is FETCH or FETCH_ONE)
Populated only when wait is true and fetchType is FETCH or FETCH_ONE. The modelOutput object returned by the Timefold Platform containing the optimized assignments (routes, schedules, etc.).
score string
The score of the returned solution, e.g. 0hard/0medium/-3603soft
Populated only when wait is true.
solverStatus string
The final solver status, e.g. SOLVING_COMPLETED or TERMINATED
Populated only when wait is true.
uri string
uriURI to the stored modelOutput (populated when fetchType is STORE)
Populated only when wait is true and fetchType is STORE (the default). Points to the modelOutput JSON file written to Kestra's internal storage.