{
  "openapi": "3.1.0",
  "info": {
    "title": "OwnRoute API",
    "version": "1.0.0",
    "description": "Vehicle routing optimization API. Built on VROOM + OSRM.",
    "termsOfService": "https://ownroute.org/terms",
    "contact": { "email": "hello@ownroute.org", "url": "https://ownroute.org" }
  },
  "servers": [
    { "url": "https://api.ownroute.org/api/v1", "description": "Production" }
  ],
  "security": [{ "bearerAuth": [] }],
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "ork_live_" }
    },
    "schemas": {
      "Job": {
        "type": "object",
        "properties": {
          "id":               { "type": "string" },
          "external_id":      { "type": "string" },
          "status":           { "type": "string", "enum": ["pending", "assigned", "in_transit", "completed", "failed", "cancelled"] },
          "dropoff_lat":      { "type": "number" },
          "dropoff_lng":      { "type": "number" },
          "dropoff_address":  { "type": "string" },
          "service_minutes":  { "type": "integer" },
          "priority":         { "type": "integer" },
          "window_start":     { "type": "string", "format": "date-time" },
          "window_end":       { "type": "string", "format": "date-time" },
          "driver_id":        { "type": "string", "nullable": true },
          "created_at":       { "type": "string", "format": "date-time" }
        }
      },
      "Driver": {
        "type": "object",
        "properties": {
          "id":                  { "type": "string" },
          "external_id":         { "type": "string" },
          "name":                { "type": "string" },
          "phone":               { "type": "string" },
          "start_lat":           { "type": "number" },
          "start_lng":           { "type": "number" },
          "max_concurrent_jobs": { "type": "integer" },
          "active":              { "type": "boolean" }
        }
      },
      "OptimizeRequest": {
        "type": "object",
        "required": ["job_ids", "driver_ids"],
        "properties": {
          "job_ids":    { "type": "array", "items": { "type": "string" } },
          "driver_ids": { "type": "array", "items": { "type": "string" } },
          "options": {
            "type": "object",
            "properties": {
              "shift_start":          { "type": "string", "format": "date-time" },
              "shift_end":            { "type": "string", "format": "date-time" },
              "max_stops_per_driver": { "type": "integer" },
              "objective":            { "type": "string", "enum": ["min_duration", "min_distance", "balanced"] },
              "seed":                 { "type": "integer" }
            }
          }
        }
      },
      "OptimizeResponse": {
        "type": "object",
        "properties": {
          "run_id":  { "type": "string" },
          "summary": {
            "type": "object",
            "properties": {
              "cost":       { "type": "number" },
              "duration_s": { "type": "integer" },
              "unassigned": { "type": "array", "items": { "type": "string" } }
            }
          },
          "routes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "driver_id": { "type": "string" },
                "stops": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "job_id":     { "type": "string" },
                      "arrival":    { "type": "string", "format": "date-time" },
                      "duration_s": { "type": "integer" }
                    }
                  }
                },
                "polyline": { "type": "string" }
              }
            }
          },
          "billing": {
            "type": "object",
            "properties": {
              "cost_usd":    { "type": "number" },
              "own_minted":  { "type": "number" },
              "balance_usd": { "type": "number" }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code":       { "type": "string" },
              "message":    { "type": "string" },
              "docs_url":   { "type": "string" },
              "top_up_url": { "type": "string" }
            }
          }
        }
      }
    }
  },
  "paths": {
    "/optimize": {
      "post": {
        "operationId": "optimize",
        "summary": "Assign jobs to drivers and return ordered routes with ETAs.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OptimizeRequest" } } }
        },
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OptimizeResponse" } } } },
          "402": { "description": "Insufficient balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/jobs": {
      "get": {
        "operationId": "listJobs",
        "summary": "List jobs.",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string" } },
          { "name": "limit",  "in": "query", "schema": { "type": "integer", "default": 50 } },
          { "name": "cursor", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "OK" } }
      },
      "post": {
        "operationId": "createJob",
        "summary": "Create a delivery job.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Job" } } } },
        "responses": { "201": { "description": "Created" } }
      }
    },
    "/jobs/{id}": {
      "get":   { "operationId": "getJob", "summary": "Get job", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } },
      "patch": { "operationId": "updateJob", "summary": "Update job", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/jobs/{id}/cancel": {
      "post": { "operationId": "cancelJob", "summary": "Cancel job", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/drivers": {
      "get":  { "operationId": "listDrivers",  "summary": "List drivers",  "responses": { "200": { "description": "OK" } } },
      "post": { "operationId": "createDriver", "summary": "Create driver", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Driver" } } } }, "responses": { "201": { "description": "Created" } } }
    },
    "/drivers/{id}": {
      "get":    { "operationId": "getDriver",    "summary": "Get driver",    "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } },
      "patch":  { "operationId": "updateDriver", "summary": "Update driver", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } },
      "delete": { "operationId": "deleteDriver", "summary": "Delete driver", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "204": { "description": "No content" } } }
    },
    "/account": {
      "get": { "operationId": "getAccount", "summary": "Get account, balance, limits", "responses": { "200": { "description": "OK" } } }
    },
    "/webhook_endpoints": {
      "get":  { "operationId": "listWebhookEndpoints", "summary": "List webhook endpoints", "responses": { "200": { "description": "OK" } } },
      "post": { "operationId": "createWebhookEndpoint", "summary": "Create webhook endpoint", "responses": { "201": { "description": "Created" } } }
    }
  }
}
