---
title: "R182 L9 + async (audit 2026-06-23) — Optimisation VRP via OR-Tools."
method: POST
path: "/api/v1/livraison/plans/{plan_id}/optimize"
tags: ["Livraison & Routing (V2)"]
---

# R182 L9 + async (audit 2026-06-23) — Optimisation VRP via OR-Tools.

`POST /api/v1/livraison/plans/{plan_id}/optimize`

## Request

- Base URL: `https://erp.eyeot.fr/api/v1`
- URL: `https://erp.eyeot.fr/api/v1/api/v1/livraison/plans/{plan_id}/optimize`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer

R182 L9 + async (audit 2026-06-23) — Optimisation VRP via OR-Tools.

    Le solver est lourd (~300s sur des plans réalistes) → exécution
    synchrone in-request = timeout 502 + worker bloqué. Désormais :

    - **petit plan + budget court** (≤ `VRP_SYNC_MAX_STOPS` stops ET
      `time_budget_sec` ≤ `VRP_SYNC_MAX_BUDGET_SEC`) → exécution SYNCHRONE,
      réponse 200 + résultat solver immédiat (comportement historique
      préservé, UX instantanée) ;
    - **sinon** → exécution ASYNCHRONE Celery, réponse **202** + `task_id`.
      Le front poll `GET /plans/<id>/optimize/<task_id>/status`.

    Body optionnel :
    - `time_budget_sec` (int 1..300, default 10) : budget temps solver
    - `vehicle_ids` (list[uuid]) : filtre véhicules autorisés
    - `async` (bool) : force l'exécution asynchrone
    - `sync` (bool) : force l'exécution synchrone (debug / petit plan)

    Réponse sync : `{ok, solver_status, routes_created, total_distance_km,
    total_duration_min, vehicles_used, stops_routed, stops_total}` ou
    `{ok: False, reason}` (no_solution / ortools_unavailable).
    Réponse async (202) : `{ok, async, status:"pending", task_id, plan_id,
    stops_total, poll_url}`.

**Permissions requises** : `livraison:dispatch`

## Response `200`

Succès — payload `{data, meta}` (cf. API-GUIDE §3.1)

## Other responses

- `201`: Ressource créée. ID dans `data.id`.
- `400`: Validation Marshmallow échouée. `errors` détaille chaque champ invalide.
- `401`: JWT manquant, expiré ou révoqué.
- `402`: L'organisation n'a pas d'abonnement actif (paywall). Rediriger vers /activate.
- `403`: Permissions `module:action` insuffisantes pour cette route.
- `404`: Ressource introuvable (ou cross-tenant — équivalent à hidden).
- `409`: État incohérent (email dupliqué, ressource déjà dans cet état, etc.).
- `422`: Validation Marshmallow échouée. `errors` détaille chaque champ invalide.
- `429`: Trop de requêtes. Honorer le header `Retry-After` (secondes).

---

[API](https://skmtc.dev/eyeot/apis/eyeot-erp-api.md) · [All operations](https://skmtc.dev/eyeot/apis/eyeot-erp-api/llms.txt) · [OpenAPI document](https://skmtc.dev/eyeot/apis/eyeot-erp-api/revisions/42ab95222a89?raw)
