# Webhooks

## Webhooks

[Webhooks](https://en.wikipedia.org/wiki/Webhook) make it possible for your application to be notified of important system events, as soon as these take place within Onfleet.

While you are generally able to create as many webhook entries as you'd like, remember that a single webhook always targets a single trigger. The following triggers are available:

<Table align={["left","left","left","left","left"]}>
  <thead>
    <tr>
      <th style={{ textAlign: "left" }}>
        ID
      </th>

      <th style={{ textAlign: "left" }}>
        Name
      </th>

      <th style={{ textAlign: "left" }}>
        Description
      </th>

      <th style={{ textAlign: "left" }}>
        Includes
      </th>

      <th style={{ textAlign: "left" }}>
        Limitations
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td style={{ textAlign: "left" }}>
        0
      </td>

      <td style={{ textAlign: "left" }}>
        taskStarted
      </td>

      <td style={{ textAlign: "left" }}>
        Task started by worker.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        None
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        1
      </td>

      <td style={{ textAlign: "left" }}>
        taskEta
      </td>

      <td style={{ textAlign: "left" }}>
        Worker ETA less than or equal to `threshold` value provided, in seconds.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`, `etaSeconds`
      </td>

      <td style={{ textAlign: "left" }}>
        Limit of 10 webhooks. Each will fire once per task, at most once every 30 seconds, when threshold is met.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        2
      </td>

      <td style={{ textAlign: "left" }}>
        taskArrival
      </td>

      <td style={{ textAlign: "left" }}>
        Worker arriving, at or closer than `threshold` value provided, in meters.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`, `distance`
      </td>

      <td style={{ textAlign: "left" }}>
        Limit of 10 webhooks. Each will fire once per task, at most once every 30 seconds, when threshold is met.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        3
      </td>

      <td style={{ textAlign: "left" }}>
        taskCompleted
      </td>

      <td style={{ textAlign: "left" }}>
        Task marked as successful.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        Task cannot be both successful and failed.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        4
      </td>

      <td style={{ textAlign: "left" }}>
        taskFailed
      </td>

      <td style={{ textAlign: "left" }}>
        Task failed.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        Task cannot be both successful and failed.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        5
      </td>

      <td style={{ textAlign: "left" }}>
        workerDuty
      </td>

      <td style={{ textAlign: "left" }}>
        Worker status changed (`0` for off-duty, `1` for on-duty).
      </td>

      <td style={{ textAlign: "left" }}>
        `workerId`, `status`, `data.worker`
      </td>

      <td style={{ textAlign: "left" }}>
        None
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        6
      </td>

      <td style={{ textAlign: "left" }}>
        taskCreated
      </td>

      <td style={{ textAlign: "left" }}>
        New task created.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        Does not include tasks created via task import from the Onfleet dashboard.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        7
      </td>

      <td style={{ textAlign: "left" }}>
        taskUpdated
      </td>

      <td style={{ textAlign: "left" }}>
        Task updated, including:

        Updated `completionDetails` (including distance, location, added timestamps, added completion/failure notes)

        When attachment ids are received under `completionDetails` field (This includes signature, photos)

        Recipient feedback has been received(when  `feedback` field is updated)
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        None
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        8
      </td>

      <td style={{ textAlign: "left" }}>
        taskDeleted
      </td>

      <td style={{ textAlign: "left" }}>
        Task deleted.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        None
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        9
      </td>

      <td style={{ textAlign: "left" }}>
        taskAssigned
      </td>

      <td style={{ textAlign: "left" }}>
        Task assigned to worker.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        This webhook will only be triggered when a Task is assigned to different containers (organization, worker, team). However, when a task is assigned during creation, it will not trigger a change of assignment as the task is just created with a direct assignment.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        10
      </td>

      <td style={{ textAlign: "left" }}>
        taskUnassigned
      </td>

      <td style={{ textAlign: "left" }}>
        Task unassigned from worker.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        None
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        12
      </td>

      <td style={{ textAlign: "left" }}>
        taskDelayed
      </td>

      <td style={{ textAlign: "left" }}>
        Task is delay time is greater than or equal to `threshold` value provided, in seconds.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`, `delay`
      </td>

      <td style={{ textAlign: "left" }}>
        Limit of 10 webhooks, applies only to active tasks, will only fire once. Only sent for active tasks.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        13
      </td>

      <td style={{ textAlign: "left" }}>
        taskCloned
      </td>

      <td style={{ textAlign: "left" }}>
        Task cloned via dashboard or API. Note that the `taskCreated` trigger will not fire when a task is cloned.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `data.task`
      </td>

      <td style={{ textAlign: "left" }}>
        None
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        14
      </td>

      <td style={{ textAlign: "left" }}>
        smsRecipientResponseMissed
      </td>

      <td style={{ textAlign: "left" }}>
        Recipient responds to a  notification via SMS, but the organization is unable to handle it at that time.
      </td>

      <td style={{ textAlign: "left" }}>
        `from`, `to`, `body`
      </td>

      <td style={{ textAlign: "left" }}>
        None
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        15
      </td>

      <td style={{ textAlign: "left" }}>
        workerCreated
      </td>

      <td style={{ textAlign: "left" }}>
        A new worker has been created.
      </td>

      <td style={{ textAlign: "left" }}>
        `adminId`, `workerId`, `actionContext` , `triggerId`,`triggerName`, `taskId`,`data.worker`, `time`
      </td>

      <td style={{ textAlign: "left" }}>
        None
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        16
      </td>

      <td style={{ textAlign: "left" }}>
        workerDeleted
      </td>

      <td style={{ textAlign: "left" }}>
        A worker has been deleted.
      </td>

      <td style={{ textAlign: "left" }}>
        `adminId`, `workerId`, `actionContext` , `triggerId`,`triggerName`, `taskId`,`data.worker`, `time`
      </td>

      <td style={{ textAlign: "left" }}>
        None.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        17
      </td>

      <td style={{ textAlign: "left" }}>
        SMSRecipientOptOut
      </td>

      <td style={{ textAlign: "left" }}>
        When a recipient replied "STOP" to opt out of SMS communications.
      </td>

      <td style={{ textAlign: "left" }}>
        `recipient`, `timestamp`, `SMS`, `triggerId`, `triggerName`,`time`
      </td>

      <td style={{ textAlign: "left" }}>
        None.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        18
      </td>

      <td style={{ textAlign: "left" }}>
        autoDispatchJobCompleted
      </td>

      <td style={{ textAlign: "left" }}>
        When Team Auto-Dispatch calculation is completed.
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `adminId`, `data.dispatch`, `dispatchId`, `taskId`, `time`, `triggerId`, `triggerName`, `workerId`
      </td>

      <td style={{ textAlign: "left" }}>
        None.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        19
      </td>

      <td style={{ textAlign: "left" }}>
        taskBatchCreateJobCompleted
      </td>

      <td style={{ textAlign: "left" }}>
        When Async Batch Tasks creation is completed.
      </td>

      <td style={{ textAlign: "left" }}>
        `status`, `tasksReceived`, `tasksCreated`, `tasksErrored`, `errors[]`, `failedTasks[]`, `newTasks[]`, `newTasksWithWarnings[]`, `workerId`, `adminId`, `taskId`, `actionContext`, `time`, `data`
      </td>

      <td style={{ textAlign: "left" }}>
        None.
      </td>
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        20
      </td>

      <td style={{ textAlign: "left" }}>
        routeOptimizationJobCompleted
      </td>

      <td style={{ textAlign: "left" }}>
        When Route Optimization is completed
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `triggerId`, `triggerName`, `taskId`, `workerId`, `adminId`, `data`, `dispatchId`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        22
      </td>

      <td style={{ textAlign: "left" }}>
        routePlanCreated
      </td>

      <td style={{ textAlign: "left" }}>
        When a Route plan is created
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `triggerId`, `triggerName`, `adminId`, `routePlanId`, `data.routePlan`, `workerId`, `data.worker`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        23
      </td>

      <td style={{ textAlign: "left" }}>
        routePlanStarted
      </td>

      <td style={{ textAlign: "left" }}>
        When a Route plan is started
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `triggerId`, `triggerName`, `adminId`, `routePlanId`, `data.routePlan`, `workerId`, `data.worker`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        24
      </td>

      <td style={{ textAlign: "left" }}>
        routePlanCompleted
      </td>

      <td style={{ textAlign: "left" }}>
        When a Route plan completed
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `triggerId`, `triggerName`, `adminId`, `routePlanId`, `data.routePlan,` `workerId`, `data.worker`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        25
      </td>

      <td style={{ textAlign: "left" }}>
        workerUpdated
      </td>

      <td style={{ textAlign: "left" }}>
        When a worker information is updated
      </td>

      <td style={{ textAlign: "left" }}>
        `workerId`, `actionContext`, `triggerId`, `triggerName`,`adminId`, `taskId`, `data`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        26
      </td>

      <td style={{ textAlign: "left" }}>
        routePlanUpdated
      </td>

      <td style={{ textAlign: "left" }}>
        When a Route plan is changed
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `triggerId`, `triggerName`, `adminId`, `routePlanId`, `data.routePlan`, `workerId`, `data.worker`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        27
      </td>

      <td style={{ textAlign: "left" }}>
        routePlanUnassigned
      </td>

      <td style={{ textAlign: "left" }}>
        When a Route Plan is unassigned
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `triggerId`, `triggerName`, `adminId`, `routePlanId`, `data.routePlan`, `workerId`, `data.worker`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        28
      </td>

      <td style={{ textAlign: "left" }}>
        routePlanAssigned
      </td>

      <td style={{ textAlign: "left" }}>
        When a Route Plan is assigned
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `triggerId`, `triggerName`, `adminId`, `routePlanId`, `data.routePlan`, `workerId`, `data.worker`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        29
      </td>

      <td style={{ textAlign: "left" }}>
        routePlanDelayed
      </td>

      <td style={{ textAlign: "left" }}>
        When a Route Plan is marked as delayed
      </td>

      <td style={{ textAlign: "left" }}>
        `actionContext`, `triggerId`, `triggerName`, `adminId`, `routePlanId`, `time`
      </td>

      <td style={{ textAlign: "left" }} />
    </tr>

    <tr>
      <td style={{ textAlign: "left" }}>
        30
      </td>

      <td style={{ textAlign: "left" }}>
        predictedTaskDelay
      </td>

      <td style={{ textAlign: "left" }}>
        Predicted task is delay time is greater than or equal to `threshold` value provided, in seconds.
      </td>

      <td style={{ textAlign: "left" }}>
        `taskId`, `actionContext`, `triggerId`, `triggerName`, `workerId,data.task`, `data.task.delayTime`, `time`
      </td>

      <td style={{ textAlign: "left" }}>
        Will be sent for tasks in an "assigned" state. Note that this is evaluated when tasks in the driver's queue are started, and messages will be sent at this point.
      </td>
    </tr>
  </tbody>
</Table>

Webhooks can be maintained via dashboard or API. All standard, non-validation requests from Onfleet to you are made via `POST`.

In addition to the properties from the *Includes* column above, the JSON body we will `POST` to your `url` will include a `time` property along with `triggerId` and `triggerName` so you may overload the same `url` on your application as required. In addition, full objects will be provided in the `data` property, as relevant. Note that all other properties not relevant to the trigger may be provided as `null`.

> 🚧 Unix Precision
>
> All time data fields returned are in milliseconds precision, with the exception of `etaSeconds`, which is in seconds.