{
  "openapi": "3.1.0",
  "info": {
    "title": "ORTEC Control Tower — Data API",
    "version": "1",
    "description": "Read-only access to route execution data: planned and realized routes, stops and proof-of-delivery attachments. Pull on your own schedule or subscribe to webhooks."
  },
  "servers": [
    {
      "url": "https://integration-[customer].ortec-xs.com/api/v1",
      "description": "Your customer environment"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "oauth2",
        "description": "OAuth 2.0 client-credentials. Request an access token from the token URL with grant_type=client_credentials, your client_id and your client_secret, then send it as: Authorization: Bearer {access_token}.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://integration-[customer].ortec-xs.com/oauth/token",
            "scopes": {}
          }
        }
      }
    },
    "schemas": {
      "Route": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "department": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date"
          },
          "status": {
            "type": "string",
            "enum": [
              "planned",
              "active",
              "completed"
            ]
          },
          "label": {
            "type": "string"
          },
          "shift": {
            "type": "string",
            "description": "Absent when the planning system does not provide a shift."
          },
          "driver": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "code": {
                "type": "string",
                "description": "Absent when the planning system does not provide a separate code."
              }
            }
          },
          "vehicle": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "trailer": {
                "type": "string",
                "description": "Absent when the planning system does not provide a trailer."
              }
            }
          },
          "planned": {
            "type": "object",
            "properties": {
              "start": {
                "type": "string",
                "format": "date-time"
              },
              "finish": {
                "type": "string",
                "format": "date-time"
              },
              "distanceKm": {
                "type": "number"
              }
            }
          },
          "realized": {
            "type": "object",
            "description": "Absent until they occur.",
            "properties": {
              "start": {
                "type": "string",
                "format": "date-time"
              },
              "finish": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "depotDeparture": {
            "type": "object",
            "properties": {
              "planned": {
                "type": "string",
                "format": "date-time"
              },
              "actual": {
                "type": "string",
                "format": "date-time"
              },
              "deltaMinutes": {
                "type": "number"
              },
              "late": {
                "type": "boolean"
              }
            }
          },
          "stops": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "sequence": {
                  "type": "integer",
                  "description": "Driving order."
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "planned",
                    "arrived",
                    "completed",
                    "deviations",
                    "cancelled"
                  ]
                },
                "type": {
                  "type": "string",
                  "description": "Stop kind from the plan, e.g. Start, Delivery, Break, End."
                },
                "isDepot": {
                  "type": "boolean"
                },
                "location": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "address": {
                      "type": "string"
                    },
                    "latitude": {
                      "type": "number"
                    },
                    "longitude": {
                      "type": "number"
                    },
                    "timezone": {
                      "type": "string"
                    }
                  }
                },
                "timeWindow": {
                  "type": "object",
                  "properties": {
                    "from": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "till": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "planned": {
                  "type": "object",
                  "properties": {
                    "arrival": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "departure": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "durationMinutes": {
                      "type": "number"
                    }
                  }
                },
                "realized": {
                  "type": "object",
                  "description": "Actual times; departure is absent while work is in progress.",
                  "properties": {
                    "arrival": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "departure": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "durationMinutes": {
                      "type": "number"
                    }
                  }
                },
                "delayMinutes": {
                  "type": "number",
                  "description": "Actual vs. planned arrival; negative = early."
                },
                "deviationCode": {
                  "type": "string"
                },
                "comments": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "source": {
                        "type": "string",
                        "enum": [
                          "driver",
                          "dispatcher"
                        ]
                      },
                      "text": {
                        "type": "string"
                      },
                      "createdAt": {
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  }
                },
                "tasks": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "deliver",
                          "pickup"
                        ]
                      },
                      "orders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string"
                            },
                            "orderNumber": {
                              "type": "string"
                            },
                            "reference": {
                              "type": "string"
                            },
                            "product": {
                              "type": "string"
                            },
                            "status": {
                              "type": "string",
                              "enum": [
                                "planned",
                                "completed",
                                "deviations",
                                "cancelled"
                              ]
                            },
                            "deviationCode": {
                              "type": "string",
                              "description": "Reason code when status is deviations or cancelled."
                            },
                            "amounts": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "unit": {
                                    "type": "string",
                                    "description": "Unit code, e.g. \"l\" or \"kg\" — never assume a unit."
                                  },
                                  "planned": {
                                    "type": "number"
                                  },
                                  "realized": {
                                    "type": "number",
                                    "description": "Absent until the order has been executed."
                                  }
                                },
                                "required": [
                                  "unit",
                                  "planned"
                                ]
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "attachments": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "photo",
                          "signature"
                        ]
                      },
                      "contentType": {
                        "type": "string"
                      },
                      "href": {
                        "type": "string",
                        "description": "Download URL — call with your Bearer token."
                      },
                      "capturedAt": {
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  }
                },
                "updatedAt": {
                  "type": "string",
                  "format": "date-time",
                  "description": "UTC."
                }
              }
            },
            "description": "Present with detail=full or on GET /routes/{routeId}."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Last modification, UTC — use for delta sync."
          }
        }
      },
      "Stop": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "sequence": {
            "type": "integer",
            "description": "Driving order."
          },
          "status": {
            "type": "string",
            "enum": [
              "planned",
              "arrived",
              "completed",
              "deviations",
              "cancelled"
            ]
          },
          "type": {
            "type": "string",
            "description": "Stop kind from the plan, e.g. Start, Delivery, Break, End."
          },
          "isDepot": {
            "type": "boolean"
          },
          "location": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "address": {
                "type": "string"
              },
              "latitude": {
                "type": "number"
              },
              "longitude": {
                "type": "number"
              },
              "timezone": {
                "type": "string"
              }
            }
          },
          "timeWindow": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "format": "date-time"
              },
              "till": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "planned": {
            "type": "object",
            "properties": {
              "arrival": {
                "type": "string",
                "format": "date-time"
              },
              "departure": {
                "type": "string",
                "format": "date-time"
              },
              "durationMinutes": {
                "type": "number"
              }
            }
          },
          "realized": {
            "type": "object",
            "description": "Actual times; departure is absent while work is in progress.",
            "properties": {
              "arrival": {
                "type": "string",
                "format": "date-time"
              },
              "departure": {
                "type": "string",
                "format": "date-time"
              },
              "durationMinutes": {
                "type": "number"
              }
            }
          },
          "delayMinutes": {
            "type": "number",
            "description": "Actual vs. planned arrival; negative = early."
          },
          "deviationCode": {
            "type": "string"
          },
          "comments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "source": {
                  "type": "string",
                  "enum": [
                    "driver",
                    "dispatcher"
                  ]
                },
                "text": {
                  "type": "string"
                },
                "createdAt": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "tasks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "deliver",
                    "pickup"
                  ]
                },
                "orders": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "orderNumber": {
                        "type": "string"
                      },
                      "reference": {
                        "type": "string"
                      },
                      "product": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "planned",
                          "completed",
                          "deviations",
                          "cancelled"
                        ]
                      },
                      "deviationCode": {
                        "type": "string",
                        "description": "Reason code when status is deviations or cancelled."
                      },
                      "amounts": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "unit": {
                              "type": "string",
                              "description": "Unit code, e.g. \"l\" or \"kg\" — never assume a unit."
                            },
                            "planned": {
                              "type": "number"
                            },
                            "realized": {
                              "type": "number",
                              "description": "Absent until the order has been executed."
                            }
                          },
                          "required": [
                            "unit",
                            "planned"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "attachments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "photo",
                    "signature"
                  ]
                },
                "contentType": {
                  "type": "string"
                },
                "href": {
                  "type": "string",
                  "description": "Download URL — call with your Bearer token."
                },
                "capturedAt": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "UTC."
          }
        }
      },
      "Order": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "orderNumber": {
            "type": "string"
          },
          "reference": {
            "type": "string"
          },
          "product": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "planned",
              "completed",
              "deviations",
              "cancelled"
            ]
          },
          "deviationCode": {
            "type": "string",
            "description": "Reason code when status is deviations or cancelled."
          },
          "amounts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "unit": {
                  "type": "string",
                  "description": "Unit code, e.g. \"l\" or \"kg\" — never assume a unit."
                },
                "planned": {
                  "type": "number"
                },
                "realized": {
                  "type": "number",
                  "description": "Absent until the order has been executed."
                }
              },
              "required": [
                "unit",
                "planned"
              ]
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "Department": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          }
        }
      },
      "AttachmentMeta": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "photo",
              "signature"
            ]
          },
          "contentType": {
            "type": "string"
          },
          "href": {
            "type": "string",
            "description": "Download URL — call with your Bearer token."
          },
          "capturedAt": {
            "type": "string",
            "format": "date-time"
          },
          "signedBy": {
            "type": "string",
            "description": "Present only when the capturing system records a signer name."
          },
          "sizeBytes": {
            "type": "integer",
            "description": "Present only when the capturing system records a size."
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "description": {
            "type": "string"
          },
          "secret": {
            "type": "string",
            "description": "Only returned when the subscription is created — store it then."
          },
          "active": {
            "type": "boolean"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "nextCursor": {
            "type": "string",
            "description": "Opaque; absent on the last page."
          },
          "limit": {
            "type": "integer"
          }
        }
      }
    }
  },
  "paths": {
    "/departments": {
      "get": {
        "summary": "Departments of your organization",
        "responses": {
          "200": {
            "description": "Department list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Department"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/routes": {
      "get": {
        "summary": "List routes (filter, paginate, delta sync)",
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Routes on this day (department-local)."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Explicit time window; alternative to date."
          },
          {
            "name": "till",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "department",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true,
            "description": "Optional filter; default: all your departments."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "planned",
                "active",
                "completed"
              ]
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only routes changed after this moment (delta sync)."
          },
          {
            "name": "detail",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "summary",
                "full"
              ],
              "default": "summary"
            },
            "description": "full embeds all stops."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100,
              "maximum": 500
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Continue from a previous page."
          }
        ],
        "responses": {
          "200": {
            "description": "Route list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Route"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — respect the Retry-After header",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/routes/{routeId}": {
      "get": {
        "summary": "One route in full detail, including stops",
        "parameters": [
          {
            "name": "routeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Route",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Route"
                }
              }
            }
          },
          "404": {
            "description": "No such route in your departments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/routes/{routeId}/stops/{stopId}/attachments": {
      "get": {
        "summary": "Photos and signatures for a stop",
        "parameters": [
          {
            "name": "routeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "stopId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Attachment metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AttachmentMeta"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such route or stop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/attachments/{attachmentId}": {
      "get": {
        "summary": "Download an attachment (binary)",
        "parameters": [
          {
            "name": "attachmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Attachment binary; the response carries the correct Content-Type. Attachments are immutable."
          },
          "404": {
            "description": "No such attachment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks": {
      "post": {
        "summary": "Create a webhook subscription",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "HTTPS endpoint of yours."
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "route.started",
                        "route.completed",
                        "stop.arrived",
                        "stop.completed",
                        "stop.deviation",
                        "stop.cancelled",
                        "attachment.created"
                      ]
                    }
                  },
                  "description": {
                    "type": "string"
                  }
                },
                "required": [
                  "url",
                  "events"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscription created — store the secret now; it is shown only once.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "422": {
            "description": "Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "List your subscriptions",
        "responses": {
          "200": {
            "description": "Subscriptions (without secrets)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Webhook"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{webhookId}": {
      "delete": {
        "summary": "Delete a subscription",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "404": {
            "description": "No such webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{webhookId}/ping": {
      "post": {
        "summary": "Send a signed test event to your endpoint",
        "parameters": [
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Delivery attempt result"
          },
          "404": {
            "description": "No such webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}