> ## 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.

# Real-time re-optimization

> Trigger a recalculation following a disruption (delay, cancellation, urgent order).

There is no dedicated "re-optimize now" endpoint. A running plan is always subject to re-optimization the moment its data changes — see [Continuous and interactive optimization](/concepts/how-the-optimization-engine-works#continuous-and-interactive-optimization). Reacting to a disruption is a matter of updating the right part of the plan, not calling a separate recalculation API.

## Types of triggering disruptions

| Disruption | What changed | How to reflect it |
| - | - | - |
| A resource is running late | Its real availability window shrank | Update that resource's `workingTimeWindow` (or `departure`) in the plan's `resources` array, then `PUT /plans/{planId}` with the full plan. |
| An order is cancelled | A stop no longer needs to be served | Remove that order from the plan's `orders` array, then `PUT /plans/{planId}` with the full plan. |
| An urgent new order comes in | A new stop must be added mid-shift | Add the new order to the plan's `orders` array with a new `id`, then `PUT /plans/{planId}` with the full plan. |
| A specific resource/stop pairing must be excluded (for example, a breakdown makes a resource unable to reach a stop it was going to serve) | A resource can no longer serve a specific order | Give that resource and that stop a tag unique to the pair (for example `forbid:resource12-stop7`), add a `forbiddenAssignment` entry in `additionalConstraints` referencing it, then `PUT /plans/{planId}` with the full plan. |

Every one of these is the same operation: mutate the relevant part of your local copy of the plan, then `PUT` the whole plan back — there is no endpoint that targets a single resource or order in isolation anymore.

<Warning>
  `PUT /plans/{planId}` replaces the whole plan: resend every resource and order, not only the changes. Anything omitted from the body is removed from the plan.
</Warning>

## How this differs from a full recalculation

Submitting any of the preceding updates keeps the plan's `id` unchanged, so it isn't treated as a new problem: the engine repairs the previous solution, adjusting it only as much as needed to be valid for the new data, then keeps improving from there — it does not restart optimization from scratch. This is normally much faster than the plan's original optimization, which had to learn the problem's shape for the first time. If an older version of the plan is still optimizing when a disruption update lands, the engine drops the stale version in favor of the newest one — you never get two versions "optimized" at once.

An update only consumes credits for stops that are new or have changed — a new `id`, or a move of more than about 11 metres — and for all stops once per 24-hour period since the plan's creation. Changing resources or constraints costs nothing extra; see [Pricing and credits](/reference/pricing-and-credits#how-credits-work).

## Best practices for call frequency

* **Batch disruptions that arrive close together** into a single update where possible, rather than issuing one `PUT` per individual change — every update re-triggers optimization, and consecutive updates just cause the engine to keep abandoning a version it hasn't finished with yet.
* **Poll before you push another update.** Check the plan's `status`, or `GET /plans/{planId}/state` for a simpler single-field `optimized` check (see [How the optimization engine works](/concepts/how-the-optimization-engine-works#the-quality-vs-computation-time-trade-off)), to see whether the previous update has already settled; there's little value in sending a new disruption update while the engine is still mid-search on the last one, beyond the disruption itself needing to be reflected immediately.
* **Don't reduce `maxOptimizationDuration` for these updates** just because they feel like small edits — the field caps *this version's* remaining search time, and a busy fleet mid-shift can still take real time to re-settle around a disruption; size it the same way you would for the initial plan (see [Handling large volumes](/guides/handling-large-volumes#sizing-maxoptimizationduration-for-a-large-problem)).

## See also

* [How the optimization engine works](/concepts/how-the-optimization-engine-works) — what happens when a plan is updated with the same `id`, and the three integration patterns for retrieving a solution.
* [Handling infeasibility](/guides/handling-infeasibility) — diagnosing a disruption that leaves a stop unplannable rather than just delayed.
* [Data model](/reference/data-model) — an overview of `Resource` and `Order`, each linking to its schema in the API reference — the two objects most commonly touched by a disruption.


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