openapi: "3.0.3" info: title: OpenRouteService API description: | Open-source routing, geocoding, isochrone, distance-matrix, and VRP optimization API built on OpenStreetMap. Pelias powers geocoding; Vroom powers optimization. This spec covers the endpoints commonly used for back-end agent workflows (geocoding, matrices for VRP solvers, route ETAs, isochrones, full VRP solve). The full ORS surface (POIs, snap-to-road, elevation, optimization advanced constraints) can be added incrementally — see notes in the catalog entry. The hosted free API (`https://api.openrouteservice.org`) exposes routing, matrix, isochrones, optimization, and geocoding. Self-hosted ORS Docker covers the ORS backend endpoints (routing, matrix, isochrones, optimization); geocoding is hosted-public-API only. Auth: pass the API key in the `Authorization` header. Sign up free at https://openrouteservice.org/dev/#/signup. Rate limits (free plan, hosted): 2,000 directions/day, 500 matrix/day, 500 optimization/day, 500 isochrones/day, 1,000 geocode/day, 40/min on most endpoints. Self-hosted backend endpoints: no hosted request caps. version: "v2" contact: name: OpenRouteService url: https://openrouteservice.org servers: - url: https://api.openrouteservice.org description: Hosted free API (requires API key) security: - apiKey: [] tags: - name: directions description: Route between two or more points with ETA, distance, and geometry. - name: matrix description: Many-to-many duration / distance matrix. Primary input for VRP solvers. - name: isochrones description: Reachable-area polygons by time or distance. - name: optimization description: VRP solver (Vroom backend). Assign N jobs to M vehicles optimally. - name: geocode description: Pelias forward and reverse geocoding. paths: /v2/directions/{profile}: post: operationId: getDirections summary: Compute a route between coordinates description: | Returns the ordered route, total duration, total distance, and turn-by-turn steps. Use `driving-hgv` for service vans / heavy-goods routing (better bridge-weight and turn-restriction handling than `driving-car`). tags: [directions] parameters: - $ref: '#/components/parameters/Profile' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DirectionsRequest' responses: '200': description: Route computed content: application/json: schema: $ref: '#/components/schemas/DirectionsResponse' '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } '429': { $ref: '#/components/responses/RateLimited' } /v2/matrix/{profile}: post: operationId: getMatrix summary: Many-to-many duration / distance matrix description: | Returns an N×M matrix of durations (seconds) and/or distances (metres) between all origin / destination pairs. This is the primary input for a Vehicle Routing Problem solver — feed the matrix into or-tools VRPTW. Free-plan limits: 3,500 locations per request total (origins × destinations), or 25 with `metrics: ['duration', 'distance']`. tags: [matrix] parameters: - $ref: '#/components/parameters/Profile' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/MatrixRequest' responses: '200': description: Matrix computed content: application/json: schema: $ref: '#/components/schemas/MatrixResponse' '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } '429': { $ref: '#/components/responses/RateLimited' } /v2/isochrones/{profile}: post: operationId: getIsochrones summary: Reachable-area polygons by time or distance description: | Returns one polygon per requested location × range — the area reachable within the given travel time (seconds) or distance (metres). Useful for defining service zones, dispatcher catchment analysis, and SLA-feasibility checks at a glance. tags: [isochrones] parameters: - $ref: '#/components/parameters/Profile' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/IsochronesRequest' responses: '200': description: Isochrones computed content: application/json: schema: $ref: '#/components/schemas/IsochronesResponse' '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } '429': { $ref: '#/components/responses/RateLimited' } /optimization: post: operationId: solveOptimization summary: Solve a Vehicle Routing Problem (Vroom) description: | Assigns jobs to vehicles optimally, minimising total travel time subject to time windows, skill matching, capacity, and breaks. Backed by Vroom. Free-plan limits: 50 jobs, 3 vehicles per request. Self-hosted ORS has no such caps. For larger problems, run or-tools VRPTW locally and use only the `/v2/matrix/*` endpoint here. tags: [optimization] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/OptimizationRequest' responses: '200': description: Optimised plan content: application/json: schema: $ref: '#/components/schemas/OptimizationResponse' '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } '429': { $ref: '#/components/responses/RateLimited' } /geocode/search: get: operationId: geocodeSearch summary: Forward geocode an address or place name description: | Pelias forward geocoder. Converts a free-text address into one or more candidate coordinates with provenance, confidence, and structured address components. Restrict to a country with `boundary.country` (ISO 3166-1 alpha-2 or alpha-3) for higher-quality matches. tags: [geocode] parameters: - in: query name: text required: true schema: { type: string } description: Free-form address or place name. - in: query name: focus.point.lon schema: { type: number, format: double } description: Longitude to bias results toward. - in: query name: focus.point.lat schema: { type: number, format: double } description: Latitude to bias results toward. - in: query name: boundary.country schema: { type: string } description: ISO 3166-1 country code to restrict results to (e.g. `AU`). - in: query name: size schema: { type: integer, default: 10, minimum: 1, maximum: 40 } description: Maximum candidates to return. responses: '200': description: Geocode candidates content: application/json: schema: $ref: '#/components/schemas/GeocodeResponse' '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } '429': { $ref: '#/components/responses/RateLimited' } /geocode/reverse: get: operationId: geocodeReverse summary: Reverse-geocode a coordinate into an address description: | Returns the nearest known address(es) for a given coordinate. Pelias-backed. tags: [geocode] parameters: - in: query name: point.lon required: true schema: { type: number, format: double } description: Longitude. - in: query name: point.lat required: true schema: { type: number, format: double } description: Latitude. - in: query name: size schema: { type: integer, default: 10, minimum: 1, maximum: 40 } description: Maximum candidates to return. - in: query name: boundary.circle.radius schema: { type: number, format: double } description: Restrict to this radius (km) around the point. responses: '200': description: Reverse-geocode candidates content: application/json: schema: $ref: '#/components/schemas/GeocodeResponse' '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } '429': { $ref: '#/components/responses/RateLimited' } components: securitySchemes: apiKey: type: apiKey in: header name: Authorization description: | Free key from https://openrouteservice.org/dev/#/signup. Pass the raw key as the `Authorization` header value (no `Bearer ` prefix). The CLI reads the key from the `ORS_API_KEY` environment variable. parameters: Profile: in: path name: profile required: true schema: type: string enum: - driving-car - driving-hgv - cycling-regular - cycling-mountain - cycling-road - cycling-electric - foot-walking - foot-hiking - wheelchair description: | Routing profile. `driving-hgv` is the right pick for service vans / utility vehicles — it respects bridge weight, low-clearance, and large-vehicle turn restrictions that `driving-car` ignores. schemas: Coordinate: type: array description: '[lon, lat] pair, decimal degrees, WGS84.' items: { type: number, format: double } minItems: 2 maxItems: 2 DirectionsRequest: type: object required: [coordinates] properties: coordinates: type: array minItems: 2 maxItems: 50 items: { $ref: '#/components/schemas/Coordinate' } description: Ordered route waypoints. First is origin, last is destination. alternative_routes: type: object properties: target_count: { type: integer, minimum: 1, maximum: 3 } weight_factor: { type: number, format: double } share_factor: { type: number, format: double } units: type: string enum: [m, km, mi] default: m language: type: string description: Localisation for textual turn instructions (e.g. `en-AU`). instructions: type: boolean default: true elevation: type: boolean default: false preference: type: string enum: [fastest, shortest, recommended] default: fastest radiuses: type: array items: { type: number } description: Per-waypoint snap-radius (m). Use -1 to disable snapping for that point. DirectionsResponse: type: object properties: routes: type: array items: type: object properties: summary: type: object properties: distance: { type: number, format: double, description: 'Total distance, units depend on `units` request field.' } duration: { type: number, format: double, description: 'Total duration in seconds.' } geometry: type: string description: Polyline-encoded geometry (precision 5). segments: type: array items: type: object properties: distance: { type: number, format: double } duration: { type: number, format: double } steps: type: array items: { type: object, additionalProperties: true } bbox: type: array items: { type: number, format: double } way_points: type: array items: { type: integer } bbox: type: array items: { type: number, format: double } metadata: type: object additionalProperties: true MatrixRequest: type: object required: [locations] properties: locations: type: array minItems: 2 items: { $ref: '#/components/schemas/Coordinate' } description: All locations participating in the matrix. sources: type: array items: { type: integer } description: Indices into `locations` to use as origins. Omit to use all locations. destinations: type: array items: { type: integer } description: Indices into `locations` to use as destinations. Omit to use all locations. metrics: type: array items: { type: string, enum: [duration, distance] } default: [duration] units: type: string enum: [m, km, mi] default: m resolve_locations: type: boolean default: false MatrixResponse: type: object properties: durations: type: array description: N×M matrix of durations in seconds. items: type: array items: { type: number, format: double, nullable: true } distances: type: array description: N×M matrix of distances (units per request). items: type: array items: { type: number, format: double, nullable: true } sources: type: array items: { type: object, additionalProperties: true } destinations: type: array items: { type: object, additionalProperties: true } metadata: type: object additionalProperties: true IsochronesRequest: type: object required: [locations, range] properties: locations: type: array minItems: 1 maxItems: 5 items: { $ref: '#/components/schemas/Coordinate' } range: type: array items: { type: number, format: double } description: Time (seconds) or distance (metres) thresholds. One polygon per value, per location. range_type: type: string enum: [time, distance] default: time interval: type: number format: double description: Optional sub-interval to densify the response. attributes: type: array items: { type: string, enum: [area, reachfactor, total_pop] } smoothing: type: number format: double minimum: 0 maximum: 100 default: 0 IsochronesResponse: type: object properties: type: { type: string } bbox: type: array items: { type: number, format: double } features: type: array items: type: object properties: type: { type: string } properties: type: object additionalProperties: true geometry: type: object additionalProperties: true metadata: type: object additionalProperties: true OptimizationRequest: type: object required: [jobs, vehicles] properties: jobs: type: array items: type: object required: [id, location] properties: id: { type: integer } location: type: array items: { type: number, format: double } minItems: 2 maxItems: 2 service: { type: integer, description: 'On-site service duration in seconds.' } amount: type: array items: { type: integer } description: Capacity demand vector (matches vehicle.capacity dimensions). skills: type: array items: { type: integer } time_windows: type: array items: type: array items: { type: integer, description: 'Unix epoch seconds.' } minItems: 2 maxItems: 2 priority: { type: integer, minimum: 0, maximum: 100 } vehicles: type: array items: type: object required: [id, profile] properties: id: { type: integer } profile: type: string enum: - driving-car - driving-hgv - cycling-regular - cycling-mountain - cycling-road - cycling-electric - foot-walking - foot-hiking - wheelchair start: type: array items: { type: number, format: double } minItems: 2 maxItems: 2 end: type: array items: { type: number, format: double } minItems: 2 maxItems: 2 capacity: type: array items: { type: integer } skills: type: array items: { type: integer } time_window: type: array items: { type: integer } minItems: 2 maxItems: 2 breaks: type: array items: type: object properties: id: { type: integer } service: { type: integer } time_windows: type: array items: type: array items: { type: integer } minItems: 2 maxItems: 2 options: type: object properties: g: { type: boolean, description: 'Include route geometries in response.' } OptimizationResponse: type: object properties: code: { type: integer, description: '0 = success.' } summary: type: object properties: cost: { type: integer } duration: { type: integer } distance: { type: integer } unassigned: { type: integer } service: { type: integer } waiting_time: { type: integer } routes: type: array items: type: object properties: vehicle: { type: integer } steps: type: array items: type: object properties: type: { type: string, enum: [start, job, break, end] } location: type: array items: { type: number, format: double } job: { type: integer } service: { type: integer } waiting_time: { type: integer } arrival: { type: integer } duration: { type: integer } cost: { type: integer } duration: { type: integer } distance: { type: integer } service: { type: integer } waiting_time: { type: integer } geometry: { type: string } unassigned: type: array items: type: object properties: id: { type: integer } location: type: array items: { type: number, format: double } reason: { type: string } GeocodeResponse: type: object properties: type: { type: string, enum: [FeatureCollection] } bbox: type: array items: { type: number, format: double } features: type: array items: type: object properties: type: { type: string } geometry: type: object properties: type: { type: string, enum: [Point] } coordinates: type: array items: { type: number, format: double } minItems: 2 maxItems: 2 properties: type: object properties: id: { type: string } gid: { type: string } layer: { type: string } source: { type: string } name: { type: string } confidence: { type: number, format: double } accuracy: { type: string } country: { type: string } country_a: { type: string, description: 'ISO 3166 alpha-3.' } region: { type: string } locality: { type: string } street: { type: string } housenumber: { type: string } postalcode: { type: string } label: { type: string, description: 'Human-readable full address.' } geocoding: type: object additionalProperties: true ApiError: type: object properties: error: type: object properties: code: { type: integer } message: { type: string } info: type: object properties: engine: type: object additionalProperties: true attribution: { type: string } timestamp: { type: integer } responses: BadRequest: description: Malformed request content: application/json: schema: { $ref: '#/components/schemas/ApiError' } Unauthorized: description: API key missing or invalid content: application/json: schema: { $ref: '#/components/schemas/ApiError' } RateLimited: description: Per-minute or daily quota exhausted content: application/json: schema: { $ref: '#/components/schemas/ApiError' }