{
  "openapi": "3.1.0",
  "info": {
    "title": "Raute Partner API",
    "version": "1.0.0",
    "summary": "Push delivery orders into Raute and read tracking back out.",
    "description": "Raute plans multi-stop delivery routes, tracks drivers live and captures proof of delivery. This API is how another system hands Raute the stops it needs delivered and reads back where each one is.\n\nKeys are issued by the account holder at https://www.raute.io/api-keys and are available on every plan. A key belongs to one company and can only ever see that company's data; the company is taken from the key, never from the request.",
    "contact": { "name": "Raute", "url": "https://www.raute.io/developers" }
  },
  "servers": [{ "url": "https://www.raute.io/api/v1" }],
  "security": [{ "apiKey": [] }],
  "tags": [
    { "name": "Orders", "description": "Create, read, update and cancel delivery orders." },
    { "name": "Tracking", "description": "Where an order is, its ETA and its driver." },
    { "name": "Drivers", "description": "Read drivers and link them to ids in your own system." }
  ],
  "paths": {
    "/orders": {
      "get": {
        "tags": ["Orders"],
        "summary": "List orders",
        "description": "Requires the orders:read scope.",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "$ref": "#/components/schemas/OrderStatus" } },
          { "name": "delivery_date", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "source", "in": "query", "description": "Filter to orders created with this external_source.", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": {
            "description": "A page of orders.",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Order" } } }
            } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "tags": ["Orders"],
        "summary": "Create an order",
        "description": "Requires the orders:write scope. The address is geocoded on creation. If it cannot be placed on the map the order is still created and the response carries a warning, but the stop will not appear on a route until the address is corrected.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NewOrder" } } }
        },
        "responses": {
          "201": {
            "description": "The order was created.",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "data": { "$ref": "#/components/schemas/Order" },
                "created": { "type": "boolean" },
                "warning": { "type": ["string", "null"], "description": "Present when the address could not be geocoded." }
              }
            } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/orders/{id}": {
      "parameters": [
        { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "The Raute order id, or your own external_id when source is supplied." },
        { "name": "source", "in": "query", "schema": { "type": "string" }, "description": "Set this to resolve id as your own external_id rather than a Raute id." }
      ],
      "get": {
        "tags": ["Orders"],
        "summary": "Read one order",
        "description": "Requires the orders:read scope.",
        "responses": {
          "200": { "description": "The order.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Order" } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": ["Orders"],
        "summary": "Update an order",
        "description": "Requires the orders:write scope. Cannot assign a driver or mark an order delivered.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderPatch" } } } },
        "responses": {
          "200": { "description": "The updated order.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Order" } } } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "tags": ["Orders"],
        "summary": "Cancel an order",
        "description": "Requires the orders:write scope.",
        "parameters": [{ "name": "reason", "in": "query", "schema": { "type": "string", "default": "Cancelled via partner API" } }],
        "responses": {
          "200": { "description": "The order was cancelled." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/orders/{id}/tracking": {
      "get": {
        "tags": ["Tracking"],
        "summary": "Track one order",
        "description": "Accepts either the tracking:read or the orders:read scope. This is the narrowest useful endpoint and the right one behind a customer-facing tracking page.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "source", "in": "query", "schema": { "type": "string" }, "description": "Set this to resolve id as your own external_id." }
        ],
        "responses": {
          "200": { "description": "Tracking for the order.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Tracking" } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/orders/tracking": {
      "get": {
        "tags": ["Tracking"],
        "summary": "Look up tracking without a Raute id",
        "description": "Accepts either the tracking:read or the orders:read scope. Give order_id, or give external_id together with source.",
        "parameters": [
          { "name": "order_id", "in": "query", "schema": { "type": "string" } },
          { "name": "external_id", "in": "query", "schema": { "type": "string" } },
          { "name": "source", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Tracking for the order.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Tracking" } } } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/drivers": {
      "get": {
        "tags": ["Drivers"],
        "summary": "List drivers",
        "description": "Requires the orders:read scope, not the narrower tracking scope.",
        "parameters": [
          { "name": "source", "in": "query", "schema": { "type": "string" } },
          { "name": "unlinked", "in": "query", "schema": { "type": "string" }, "description": "Return only drivers with no external id for this source." }
        ],
        "responses": {
          "200": { "description": "The company's drivers.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Driver" } } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" }
        }
      }
    },
    "/drivers/{id}": {
      "patch": {
        "tags": ["Drivers"],
        "summary": "Link a driver to an id in your own system",
        "description": "Requires the orders:write scope.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": {
            "type": "object",
            "properties": {
              "external_source": { "type": "string" },
              "external_id": { "type": "string" }
            }
          } } }
        },
        "responses": {
          "200": { "description": "The updated driver.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Driver" } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "A key created at https://www.raute.io/api-keys. The secret is shown once at creation and never again, because only its hash is stored. Each key carries scopes: tracking:read, orders:read, orders:write."
      }
    },
    "responses": {
      "BadRequest": { "description": "The request was malformed or a required field was missing.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Unauthorized": { "description": "The key is missing, unknown or revoked.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "InsufficientScope": { "description": "The key is valid but does not carry the scope this endpoint needs.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "No such record on this company.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "RateLimited": { "description": "Too many requests. Read and write limits are set per key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string", "examples": ["insufficient_scope", "missing_field", "invalid_json"] },
              "message": { "type": "string" }
            }
          }
        }
      },
      "OrderStatus": {
        "type": "string",
        "enum": ["pending", "assigned", "in_progress", "delivered", "cancelled"]
      },
      "NewOrder": {
        "type": "object",
        "required": ["customer_name", "address"],
        "properties": {
          "customer_name": { "type": "string" },
          "address": { "type": "string", "description": "A full street address. It is geocoded on creation." },
          "city": { "type": ["string", "null"] },
          "state": { "type": ["string", "null"] },
          "zip_code": { "type": ["string", "null"] },
          "phone": { "type": ["string", "null"] },
          "notes": { "type": "string" },
          "order_type": { "type": "string", "enum": ["delivery", "pickup"], "default": "delivery" },
          "order_number": { "type": ["string", "null"], "description": "Your own human readable number. Generated if omitted." },
          "external_id": { "type": ["string", "null"], "description": "The id of this order in your system. Lets you address it later without storing Raute ids." },
          "source": { "type": "string", "default": "api", "description": "A name for your system, used with external_id to address orders." },
          "delivery_date": { "type": ["string", "null"], "format": "date" },
          "time_window_start": { "type": ["string", "null"] },
          "time_window_end": { "type": ["string", "null"] }
        }
      },
      "OrderPatch": {
        "type": "object",
        "description": "Any subset of the writable fields on NewOrder. A driver cannot be assigned and an order cannot be marked delivered through this API.",
        "properties": {
          "customer_name": { "type": "string" },
          "address": { "type": "string" },
          "city": { "type": "string" },
          "state": { "type": "string" },
          "zip_code": { "type": "string" },
          "phone": { "type": "string" },
          "notes": { "type": "string" },
          "delivery_date": { "type": "string", "format": "date" },
          "time_window_start": { "type": "string" },
          "time_window_end": { "type": "string" }
        }
      },
      "Order": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "order_number": { "type": ["string", "null"] },
          "external_id": { "type": ["string", "null"] },
          "external_source": { "type": ["string", "null"] },
          "status": { "$ref": "#/components/schemas/OrderStatus" },
          "customer_name": { "type": ["string", "null"] },
          "phone": { "type": ["string", "null"] },
          "address": { "type": ["string", "null"] },
          "city": { "type": ["string", "null"] },
          "state": { "type": ["string", "null"] },
          "zip_code": { "type": ["string", "null"] },
          "latitude": { "type": ["number", "null"] },
          "longitude": { "type": ["number", "null"] },
          "notes": { "type": ["string", "null"] },
          "order_type": { "type": ["string", "null"] },
          "delivery_date": { "type": ["string", "null"], "format": "date" },
          "time_window_start": { "type": ["string", "null"] },
          "time_window_end": { "type": ["string", "null"] },
          "estimated_arrival": { "type": ["string", "null"] },
          "driver_id": { "type": ["string", "null"] },
          "delivered_at": { "type": ["string", "null"], "format": "date-time" },
          "delivered_lat": { "type": ["number", "null"] },
          "delivered_lng": { "type": ["number", "null"] },
          "signature_url": { "type": ["string", "null"] },
          "proof_url": { "type": ["string", "null"], "description": "Photo captured at the door." },
          "signed_by_name": { "type": ["string", "null"] },
          "signature_required": { "type": ["boolean", "null"] },
          "route_index": { "type": ["integer", "null"], "description": "Position of this stop on the driver's route." },
          "tracking_token": { "type": ["string", "null"] },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        }
      },
      "Tracking": {
        "type": "object",
        "description": "Where the order is, when it is expected and who is carrying it.",
        "properties": {
          "status": { "$ref": "#/components/schemas/OrderStatus" },
          "estimated_arrival": { "type": ["string", "null"] },
          "route_index": { "type": ["integer", "null"] },
          "delivered_at": { "type": ["string", "null"], "format": "date-time" },
          "proof_url": { "type": ["string", "null"] },
          "signature_url": { "type": ["string", "null"] },
          "driver": { "$ref": "#/components/schemas/Driver" }
        }
      },
      "Driver": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": ["string", "null"] },
          "phone": { "type": ["string", "null"] },
          "email": { "type": ["string", "null"] },
          "external_id": { "type": ["string", "null"] },
          "external_source": { "type": ["string", "null"] }
        }
      }
    }
  }
}
