{
 "openapi": "3.1.0",
 "info": {
  "title": "Fleet It API",
  "version": "1.0.0",
  "description": "Create deliveries, manage riders and follow every job to the door. All requests and responses are JSON. Money is always an integer in minor units (cents)."
 },
 "servers": [
  {
   "url": "/",
   "description": "This server"
  }
 ],
 "tags": [
  {
   "name": "Jobs",
   "description": "Deliveries: create them, follow them, change them."
  },
  {
   "name": "Riders",
   "description": "The people who deliver."
  },
  {
   "name": "Webhooks",
   "description": "Be told when something happens instead of asking."
  },
  {
   "name": "Account",
   "description": "Dispatch and pricing settings."
  },
  {
   "name": "Insight",
   "description": "Numbers for dashboards."
  },
  {
   "name": "Tracking",
   "description": "What your customer sees."
  },
  {
   "name": "Rider app",
   "description": "Endpoints a rider's app calls with the rider's own token."
  }
 ],
 "components": {
  "securitySchemes": {
   "apiKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "An API key from the console (starts `dk_`), sent as `Authorization: Bearer dk_\u2026`. Use it from your server only."
   },
   "riderToken": {
    "type": "http",
    "scheme": "bearer",
    "description": "A rider's token (starts `wk_`), returned once when the rider is created."
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "object",
      "properties": {
       "code": {
        "type": "string",
        "description": "Stable, machine-readable reason, e.g. `invalid_transition`."
       },
       "message": {
        "type": "string",
        "description": "Human-readable explanation."
       }
      },
      "required": [
       "code",
       "message"
      ]
     }
    },
    "required": [
     "error"
    ]
   },
   "StopInput": {
    "type": "object",
    "properties": {
     "lat": {
      "type": "number",
      "description": "Latitude, -90 to 90."
     },
     "lng": {
      "type": "number",
      "description": "Longitude, -180 to 180."
     },
     "address": {
      "type": "string"
     },
     "name": {
      "type": "string",
      "description": "Business or person at this stop."
     },
     "phone": {
      "type": "string"
     }
    },
    "required": [
     "lat",
     "lng"
    ]
   },
   "Stop": {
    "type": "object",
    "properties": {
     "lat": {
      "type": "number"
     },
     "lng": {
      "type": "number"
     },
     "address": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     }
    },
    "required": [
     "lat",
     "lng",
     "address",
     "name",
     "phone"
    ]
   },
   "JobState": {
    "type": "string",
    "enum": [
     "searching",
     "assigned",
     "at_pickup",
     "picked_up",
     "at_dropoff",
     "delivered",
     "failed",
     "cancelled"
    ],
    "description": "`searching` \u2192 `assigned` \u2192 `at_pickup` \u2192 `picked_up` \u2192 `at_dropoff` \u2192 `delivered`. `failed` and `cancelled` are the other ways a job ends."
   },
   "Job": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "external_ref": {
      "anyOf": [
       {
        "type": "string",
        "description": "Your own reference, e.g. an order number."
       },
       {
        "type": "null"
       }
      ]
     },
     "state": {
      "$ref": "#/components/schemas/JobState"
     },
     "pickup": {
      "$ref": "#/components/schemas/Stop"
     },
     "dropoff": {
      "$ref": "#/components/schemas/Stop"
     },
     "ready_at": {
      "anyOf": [
       {
        "type": "string",
        "format": "date-time",
        "description": "When the goods will be ready to collect."
       },
       {
        "type": "null"
       }
      ]
     },
     "cash_to_collect": {
      "type": "integer",
      "description": "Cash the rider must collect at the door. Money is always an integer in minor units (cents)."
     },
     "cash_collected": {
      "anyOf": [
       {
        "type": "integer"
       },
       {
        "type": "null"
       }
      ]
     },
     "notes": {
      "type": "string"
     },
     "proof": {
      "anyOf": [
       {
        "type": "object",
        "properties": {
         "photo_url": {
          "anyOf": [
           {
            "type": "string"
           },
           {
            "type": "null"
           }
          ]
         },
         "signature_url": {
          "anyOf": [
           {
            "type": "string"
           },
           {
            "type": "null"
           }
          ]
         },
         "recipient_name": {
          "anyOf": [
           {
            "type": "string"
           },
           {
            "type": "null"
           }
          ]
         },
         "notes": {
          "anyOf": [
           {
            "type": "string"
           },
           {
            "type": "null"
           }
          ]
         }
        }
       },
       {
        "type": "null"
       }
      ]
     },
     "failure_reason": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ]
     },
     "worker_id": {
      "anyOf": [
       {
        "type": "string",
        "format": "uuid"
       },
       {
        "type": "null"
       }
      ]
     },
     "tracking_url": {
      "type": "string",
      "description": "Link to give the customer. Shows live status without signing in."
     },
     "created_at": {
      "type": "string",
      "format": "date-time"
     },
     "assigned_at": {
      "anyOf": [
       {
        "type": "string",
        "format": "date-time"
       },
       {
        "type": "null"
       }
      ]
     },
     "picked_up_at": {
      "anyOf": [
       {
        "type": "string",
        "format": "date-time"
       },
       {
        "type": "null"
       }
      ]
     },
     "completed_at": {
      "anyOf": [
       {
        "type": "string",
        "format": "date-time"
       },
       {
        "type": "null"
       }
      ]
     }
    },
    "required": [
     "id",
     "state",
     "pickup",
     "dropoff",
     "cash_to_collect",
     "tracking_url",
     "created_at"
    ]
   },
   "NewJob": {
    "type": "object",
    "properties": {
     "pickup": {
      "$ref": "#/components/schemas/StopInput"
     },
     "dropoff": {
      "$ref": "#/components/schemas/StopInput"
     },
     "external_ref": {
      "type": "string"
     },
     "ready_at": {
      "type": "string",
      "format": "date-time"
     },
     "cash_to_collect": {
      "type": "integer",
      "description": "Defaults to 0 (prepaid). Money is always an integer in minor units (cents)."
     },
     "notes": {
      "type": "string"
     }
    },
    "required": [
     "pickup",
     "dropoff"
    ]
   },
   "Worker": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "name": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "vehicle": {
      "type": "string",
      "enum": [
       "bicycle",
       "motorbike",
       "car",
       "van",
       "truck",
       "foot"
      ]
     },
     "capacity": {
      "type": "integer",
      "description": "Jobs the rider can carry at once."
     },
     "cash_limit": {
      "anyOf": [
       {
        "type": "integer",
        "description": "The most cash the rider may hold; null for no limit."
       },
       {
        "type": "null"
       }
      ]
     },
     "cash_on_hand": {
      "type": "integer"
     },
     "on_duty": {
      "type": "boolean"
     },
     "online": {
      "type": "boolean",
      "description": "On duty and heard from recently enough to be offered work."
     },
     "active_jobs": {
      "type": "integer"
     },
     "last_lat": {
      "anyOf": [
       {
        "type": "number"
       },
       {
        "type": "null"
       }
      ]
     },
     "last_lng": {
      "anyOf": [
       {
        "type": "number"
       },
       {
        "type": "null"
       }
      ]
     },
     "last_seen_at": {
      "anyOf": [
       {
        "type": "string",
        "format": "date-time"
       },
       {
        "type": "null"
       }
      ]
     }
    },
    "required": [
     "id",
     "name",
     "phone",
     "vehicle",
     "capacity",
     "cash_on_hand",
     "on_duty",
     "online",
     "active_jobs"
    ]
   },
   "NewWorker": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string"
     },
     "phone": {
      "type": "string",
      "description": "5 to 20 digits, optionally starting with +. Unique per account."
     },
     "vehicle": {
      "type": "string"
     },
     "capacity": {
      "type": "integer"
     },
     "cash_limit": {
      "anyOf": [
       {
        "type": "integer"
       },
       {
        "type": "null"
       }
      ]
     }
    },
    "required": [
     "name",
     "phone"
    ]
   },
   "Settings": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "name": {
      "type": "string"
     },
     "offer_timeout_s": {
      "type": "integer",
      "description": "Seconds a rider has to answer an offer (5\u2013600)."
     },
     "search_radius_m": {
      "type": "integer",
      "description": "How far from the pickup to look for riders (200\u201350000)."
     },
     "webhook_url": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ]
     },
     "hold_for_prep": {
      "type": "boolean",
      "description": "Hold a job back until a rider would arrive about when the goods are ready."
     },
     "fee_base": {
      "type": "integer",
      "description": "Money is always an integer in minor units (cents)."
     },
     "fee_per_km": {
      "type": "integer",
      "description": "Money is always an integer in minor units (cents)."
     },
     "surge_max": {
      "type": "number",
      "description": "Highest busy-area multiplier, 1\u20135. 1 switches it off."
     },
     "eta_factor": {
      "type": "number",
      "description": "Learned: real travel time divided by the estimate. Read-only."
     },
     "eta_samples": {
      "type": "integer"
     }
    }
   },
   "Quote": {
    "type": "object",
    "properties": {
     "fee": {
      "type": "integer",
      "description": "Money is always an integer in minor units (cents)."
     },
     "multiplier": {
      "type": "number",
      "description": "1.0 normally; higher when the area has more orders than free riders."
     },
     "distance_m": {
      "type": "integer"
     },
     "trip_s": {
      "type": "integer",
      "description": "Estimated travel time from pickup to drop-off."
     },
     "pickup_eta_s": {
      "anyOf": [
       {
        "type": "integer",
        "description": "How soon a free rider could reach the pickup; null if none is in range."
       },
       {
        "type": "null"
       }
      ]
     },
     "riders_in_range": {
      "type": "integer"
     },
     "free_riders_nearby": {
      "type": "integer"
     },
     "orders_waiting_nearby": {
      "type": "integer"
     }
    }
   },
   "Offer": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "expires_at": {
      "type": "integer",
      "description": "Unix seconds."
     },
     "seconds_left": {
      "type": "integer"
     },
     "eta_to_pickup_s": {
      "type": "integer"
     },
     "trip_distance_m": {
      "type": "integer"
     },
     "job": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string",
        "format": "uuid"
       },
       "pickup": {
        "type": "object",
        "properties": {}
       },
       "dropoff": {
        "type": "object",
        "properties": {}
       },
       "cash_to_collect": {
        "type": "integer"
       },
       "ready_at": {
        "anyOf": [
         {
          "type": "integer"
         },
         {
          "type": "null"
         }
        ]
       }
      },
      "description": "Contact details are held back until the rider accepts."
     }
    }
   },
   "Progress": {
    "oneOf": [
     {
      "type": "object",
      "properties": {
       "type": {
        "const": "arrived_pickup"
       }
      },
      "required": [
       "type"
      ]
     },
     {
      "type": "object",
      "properties": {
       "type": {
        "const": "picked_up"
       }
      },
      "required": [
       "type"
      ]
     },
     {
      "type": "object",
      "properties": {
       "type": {
        "const": "arrived_dropoff"
       }
      },
      "required": [
       "type"
      ]
     },
     {
      "type": "object",
      "properties": {
       "type": {
        "const": "delivered"
       },
       "proof": {
        "type": "object",
        "properties": {
         "photo_url": {
          "type": "string"
         },
         "signature_url": {
          "type": "string"
         },
         "recipient_name": {
          "type": "string"
         },
         "notes": {
          "type": "string"
         }
        }
       },
       "cash_collected": {
        "type": "integer",
        "description": "Defaults to the amount the job asked for."
       }
      },
      "required": [
       "type"
      ]
     },
     {
      "type": "object",
      "properties": {
       "type": {
        "const": "failed"
       },
       "reason": {
        "type": "string"
       }
      },
      "required": [
       "type",
       "reason"
      ]
     }
    ],
    "description": "What the rider reports. Arrivals are also detected automatically from the rider's position."
   },
   "PlanStop": {
    "type": "object",
    "properties": {
     "job_id": {
      "type": "string",
      "format": "uuid"
     },
     "kind": {
      "type": "string",
      "enum": [
       "pickup",
       "dropoff"
      ]
     },
     "lat": {
      "type": "number"
     },
     "lng": {
      "type": "number"
     },
     "name": {
      "type": "string"
     },
     "address": {
      "type": "string"
     },
     "phone": {
      "type": "string"
     },
     "cash_to_collect": {
      "type": "integer"
     },
     "external_ref": {
      "anyOf": [
       {
        "type": "string"
       },
       {
        "type": "null"
       }
      ]
     }
    }
   },
   "Tracking": {
    "type": "object",
    "properties": {
     "state": {
      "$ref": "#/components/schemas/JobState"
     },
     "pickup": {
      "type": "object",
      "properties": {}
     },
     "dropoff": {
      "type": "object",
      "properties": {}
     },
     "rider": {
      "anyOf": [
       {
        "type": "object",
        "properties": {
         "name": {
          "type": "string",
          "description": "First name only."
         },
         "vehicle": {
          "type": "string"
         },
         "position": {
          "anyOf": [
           {
            "type": "object",
            "properties": {
             "lat": {
              "type": "number"
             },
             "lng": {
              "type": "number"
             }
            }
           },
           {
            "type": "null"
           }
          ]
         },
         "position_at_ms": {
          "anyOf": [
           {
            "type": "integer"
           },
           {
            "type": "null"
           }
          ]
         }
        }
       },
       {
        "type": "null"
       }
      ]
     },
     "eta_s": {
      "anyOf": [
       {
        "type": "integer"
       },
       {
        "type": "null"
       }
      ]
     },
     "route": {
      "anyOf": [
       {
        "type": "array",
        "items": {
         "type": "object",
         "properties": {
          "lat": {
           "type": "number"
          },
          "lng": {
           "type": "number"
          }
         }
        }
       },
       {
        "type": "null"
       }
      ]
     },
     "created_at": {
      "type": "integer"
     },
     "picked_up_at": {
      "anyOf": [
       {
        "type": "integer"
       },
       {
        "type": "null"
       }
      ]
     },
     "completed_at": {
      "anyOf": [
       {
        "type": "integer"
       },
       {
        "type": "null"
       }
      ]
     }
    }
   },
   "WebhookEvent": {
    "type": "object",
    "properties": {
     "id": {
      "type": "integer",
      "description": "Increases with every event. De-duplicate and order on this."
     },
     "type": {
      "type": "string",
      "description": "e.g. `job.delivered`."
     },
     "job_id": {
      "type": "string",
      "format": "uuid"
     },
     "created_at": {
      "type": "integer",
      "description": "Unix seconds."
     },
     "data": {
      "type": "object",
      "properties": {
       "job": {
        "$ref": "#/components/schemas/Job"
       }
      }
     }
    },
    "description": "The body POSTed to your webhook address."
   }
  }
 },
 "paths": {
  "/v1/jobs": {
   "post": {
    "tags": [
     "Jobs"
    ],
    "summary": "Create a job",
    "responses": {
     "201": {
      "description": "Created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "200": {
      "description": "This Idempotency-Key was already used; the original job is returned.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Creates a delivery and starts looking for a rider straight away.",
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/NewJob"
       }
      }
     }
    },
    "parameters": [
     {
      "name": "Idempotency-Key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "Any unique string per order. Retrying with the same key never creates a second delivery."
     }
    ]
   },
   "get": {
    "tags": [
     "Jobs"
    ],
    "summary": "List jobs",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "jobs": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Job"
           }
          },
          "next_before": {
           "anyOf": [
            {
             "type": "string",
             "format": "uuid"
            },
            {
             "type": "null"
            }
           ]
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "state",
      "in": "query",
      "required": false,
      "schema": {
       "$ref": "#/components/schemas/JobState"
      },
      "description": "Only jobs in this state."
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer"
      },
      "description": "1\u2013200, default 50."
     },
     {
      "name": "before",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "format": "uuid"
      },
      "description": "Pass `next_before` from the previous page."
     }
    ]
   }
  },
  "/v1/jobs/{id}": {
   "get": {
    "tags": [
     "Jobs"
    ],
    "summary": "Get a job",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Job id"
     }
    ]
   }
  },
  "/v1/jobs/{id}/events": {
   "get": {
    "tags": [
     "Jobs"
    ],
    "summary": "Get a job's history",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "events": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "integer"
             },
             "type": {
              "type": "string"
             },
             "created_at": {
              "type": "integer"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Job id"
     }
    ]
   }
  },
  "/v1/jobs/{id}/route": {
   "get": {
    "tags": [
     "Jobs"
    ],
    "summary": "Get the route still to travel",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "points": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "lat": {
              "type": "number"
             },
             "lng": {
              "type": "number"
             }
            }
           }
          },
          "duration_s": {
           "type": "number"
          },
          "distance_m": {
           "type": "number"
          },
          "source": {
           "type": "string",
           "enum": [
            "road",
            "straight"
           ]
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Job id"
     }
    ]
   }
  },
  "/v1/jobs/{id}/cancel": {
   "post": {
    "tags": [
     "Jobs"
    ],
    "summary": "Cancel a job",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Allowed until the rider has picked the goods up.",
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Job id"
     }
    ]
   }
  },
  "/v1/jobs/{id}/assign": {
   "post": {
    "tags": [
     "Jobs"
    ],
    "summary": "Assign a job to a rider",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Skips the offer and gives a waiting job to a named rider.",
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "worker_id": {
          "type": "string",
          "format": "uuid"
         }
        },
        "required": [
         "worker_id"
        ]
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Job id"
     }
    ]
   }
  },
  "/v1/jobs/{id}/unassign": {
   "post": {
    "tags": [
     "Jobs"
    ],
    "summary": "Put a job back in the queue",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Job id"
     }
    ]
   }
  },
  "/v1/quotes": {
   "post": {
    "tags": [
     "Jobs"
    ],
    "summary": "Quote a delivery",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Quote"
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Fee, distance and pickup time before the order is placed. Nothing is created.",
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "pickup": {
          "type": "object",
          "properties": {
           "lat": {
            "type": "number"
           },
           "lng": {
            "type": "number"
           }
          },
          "required": [
           "lat",
           "lng"
          ]
         },
         "dropoff": {
          "type": "object",
          "properties": {
           "lat": {
            "type": "number"
           },
           "lng": {
            "type": "number"
           }
          },
          "required": [
           "lat",
           "lng"
          ]
         }
        },
        "required": [
         "pickup",
         "dropoff"
        ]
       }
      }
     }
    }
   }
  },
  "/v1/workers": {
   "post": {
    "tags": [
     "Riders"
    ],
    "summary": "Add a rider",
    "responses": {
     "201": {
      "description": "Created",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "worker": {
           "$ref": "#/components/schemas/Worker"
          },
          "token": {
           "type": "string",
           "description": "The rider's token. Shown once."
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/NewWorker"
       }
      }
     }
    }
   },
   "get": {
    "tags": [
     "Riders"
    ],
    "summary": "List riders",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "workers": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Worker"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/workers/{id}": {
   "get": {
    "tags": [
     "Riders"
    ],
    "summary": "Get a rider",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Worker"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Rider id"
     }
    ]
   },
   "delete": {
    "tags": [
     "Riders"
    ],
    "summary": "Remove a rider",
    "responses": {
     "204": {
      "description": "Done, no content."
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Refused while the rider has jobs in hand or cash outstanding.",
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Rider id"
     }
    ]
   }
  },
  "/v1/workers/{id}/token": {
   "post": {
    "tags": [
     "Riders"
    ],
    "summary": "Replace a rider's token",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "token": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Rider id"
     }
    ]
   }
  },
  "/v1/workers/{id}/settle": {
   "post": {
    "tags": [
     "Riders"
    ],
    "summary": "Record cash handed in",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "cash_on_hand": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "amount": {
          "type": "integer",
          "description": "Money is always an integer in minor units (cents)."
         },
         "note": {
          "type": "string"
         }
        },
        "required": [
         "amount"
        ]
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Rider id"
     }
    ]
   }
  },
  "/v1/settings": {
   "get": {
    "tags": [
     "Account"
    ],
    "summary": "Get settings",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Settings"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   },
   "patch": {
    "tags": [
     "Account"
    ],
    "summary": "Change settings",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Settings"
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "offer_timeout_s": {
          "type": "integer",
          "description": "Seconds a rider has to answer an offer (5\u2013600)."
         },
         "search_radius_m": {
          "type": "integer",
          "description": "How far from the pickup to look for riders (200\u201350000)."
         },
         "hold_for_prep": {
          "type": "boolean",
          "description": "Hold a job back until a rider would arrive about when the goods are ready."
         },
         "fee_base": {
          "type": "integer",
          "description": "Money is always an integer in minor units (cents)."
         },
         "fee_per_km": {
          "type": "integer",
          "description": "Money is always an integer in minor units (cents)."
         },
         "surge_max": {
          "type": "number",
          "description": "Highest busy-area multiplier, 1\u20135. 1 switches it off."
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/webhook": {
   "put": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Set the webhook address",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "url": {
           "type": "string"
          },
          "secret": {
           "type": "string",
           "description": "Signing secret. Shown once; setting the address again issues a new one."
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "url": {
          "type": "string",
          "description": "Must be https and publicly reachable."
         }
        },
        "required": [
         "url"
        ]
       }
      }
     }
    }
   },
   "delete": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Remove the webhook",
    "responses": {
     "204": {
      "description": "Done, no content."
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/webhook/deliveries": {
   "get": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Recent deliveries",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "url": {
           "anyOf": [
            {
             "type": "string"
            },
            {
             "type": "null"
            }
           ]
          },
          "deliveries": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "integer"
             },
             "job_id": {
              "type": "string",
              "format": "uuid"
             },
             "type": {
              "type": "string"
             },
             "state": {
              "type": "string",
              "enum": [
               "delivered",
               "retrying",
               "queued",
               "gave_up"
              ]
             },
             "attempts": {
              "type": "integer"
             },
             "status": {
              "anyOf": [
               {
                "type": "integer"
               },
               {
                "type": "null"
               }
              ]
             },
             "error": {
              "anyOf": [
               {
                "type": "string"
               },
               {
                "type": "null"
               }
              ]
             },
             "created_at": {
              "type": "integer"
             },
             "delivered_at": {
              "anyOf": [
               {
                "type": "integer"
               },
               {
                "type": "null"
               }
              ]
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/webhook/test": {
   "post": {
    "tags": [
     "Webhooks"
    ],
    "summary": "Send a test event",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "status": {
           "anyOf": [
            {
             "type": "integer"
            },
            {
             "type": "null"
            }
           ]
          },
          "error": {
           "type": "string"
          },
          "ms": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Sends a signed `ping` event now and reports your server's answer.",
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/heatmap": {
   "get": {
    "tags": [
     "Insight"
    ],
    "summary": "Riders and waiting orders by hexagon",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "cells": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "cell": {
              "type": "string",
              "description": "H3 index, resolution 8."
             },
             "centre": {
              "type": "object",
              "properties": {}
             },
             "boundary": {
              "type": "array",
              "items": {
               "type": "object",
               "properties": {}
              }
             },
             "riders": {
              "type": "integer"
             },
             "open_jobs": {
              "type": "integer"
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ]
   }
  },
  "/v1/stats": {
   "get": {
    "tags": [
     "Insight"
    ],
    "summary": "Counts and hourly totals",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "hours": {
           "type": "integer"
          },
          "totals": {
           "type": "object",
           "properties": {}
          },
          "hourly": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {}
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "apiKey": []
     }
    ],
    "parameters": [
     {
      "name": "hours",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer"
      },
      "description": "1\u2013168, default 24."
     }
    ]
   }
  },
  "/v1/track/{token}": {
   "get": {
    "tags": [
     "Tracking"
    ],
    "summary": "Track a delivery",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Tracking"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Public: the token is the credential. Callable from any website. Never returns phone numbers or amounts.",
    "security": [],
    "parameters": [
     {
      "name": "token",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "The token at the end of a job's `tracking_url`."
     }
    ]
   }
  },
  "/v1/worker/me": {
   "get": {
    "tags": [
     "Rider app"
    ],
    "summary": "The rider's profile",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Worker"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "riderToken": []
     }
    ]
   }
  },
  "/v1/worker/duty": {
   "post": {
    "tags": [
     "Rider app"
    ],
    "summary": "Go on or off duty",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Worker"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "riderToken": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "on_duty": {
          "type": "boolean"
         }
        },
        "required": [
         "on_duty"
        ]
       }
      }
     }
    }
   }
  },
  "/v1/worker/locations": {
   "post": {
    "tags": [
     "Rider app"
    ],
    "summary": "Upload positions",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "accepted": {
           "type": "integer"
          },
          "live": {
           "type": "boolean"
          },
          "arrived": {
           "type": "array",
           "items": {
            "type": "string",
            "format": "uuid"
           },
           "description": "Jobs marked as arrived by this upload."
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Send 1\u2013200 fixes; buffer them when offline. The newest keeps the rider visible to dispatch, and being within 60 m of the next stop marks arrival.",
    "security": [
     {
      "riderToken": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "points": {
          "type": "array",
          "items": {
           "type": "object",
           "properties": {
            "lat": {
             "type": "number"
            },
            "lng": {
             "type": "number"
            },
            "at": {
             "type": "string",
             "format": "date-time"
            },
            "accuracy_m": {
             "type": "number"
            }
           },
           "required": [
            "lat",
            "lng"
           ]
          }
         }
        },
        "required": [
         "points"
        ]
       }
      }
     }
    }
   }
  },
  "/v1/worker/offers": {
   "get": {
    "tags": [
     "Rider app"
    ],
    "summary": "The offer waiting on the rider",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "offers": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Offer"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "riderToken": []
     }
    ]
   }
  },
  "/v1/worker/offers/{id}/accept": {
   "post": {
    "tags": [
     "Rider app"
    ],
    "summary": "Accept an offer",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "riderToken": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Offer id"
     }
    ]
   }
  },
  "/v1/worker/offers/{id}/decline": {
   "post": {
    "tags": [
     "Rider app"
    ],
    "summary": "Decline an offer",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "declined": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "riderToken": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Offer id"
     }
    ]
   }
  },
  "/v1/worker/jobs": {
   "get": {
    "tags": [
     "Rider app"
    ],
    "summary": "Jobs in hand",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "jobs": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Job"
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "riderToken": []
     }
    ]
   }
  },
  "/v1/worker/plan": {
   "get": {
    "tags": [
     "Rider app"
    ],
    "summary": "Stops to visit, in order",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "stops": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/PlanStop"
           }
          },
          "length_m": {
           "type": "integer"
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "riderToken": []
     }
    ]
   }
  },
  "/v1/worker/jobs/{id}/progress": {
   "post": {
    "tags": [
     "Rider app"
    ],
    "summary": "Report progress on a job",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "400": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "security": [
     {
      "riderToken": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/Progress"
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Job id"
     }
    ]
   }
  },
  "/v1/worker/jobs/{id}/release": {
   "post": {
    "tags": [
     "Rider app"
    ],
    "summary": "Give a job back",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Job"
        }
       }
      }
     },
     "401": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    },
    "description": "Allowed until the goods are picked up.",
    "security": [
     {
      "riderToken": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "Job id"
     }
    ]
   }
  },
  "/healthz": {
   "get": {
    "tags": [
     "Tracking"
    ],
    "summary": "Service health",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "postgres": {
           "type": "boolean"
          },
          "redis": {
           "type": "boolean"
          }
         }
        }
       }
      }
     }
    },
    "security": []
   }
  }
 }
}
