Files
pikebacker/schemas/openapi.yaml
2026-07-02 21:04:05 +02:00

424 lines
13 KiB
YAML

openapi: 3.1.0
info:
title: BikepackPilot API
version: 0.1.0
description: MVP API contract for bikepacking route planning, staging, POI corridor, offline packs, exports, and local reports.
servers:
- url: http://localhost:8000
paths:
/v1/trips:
post:
summary: Create trip
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TripRequest'
responses:
'201':
description: Trip created
content:
application/json:
schema:
$ref: '#/components/schemas/Trip'
/v1/routes/plan:
post:
summary: Plan a bikepacking route
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RoutePlanRequest'
responses:
'200':
description: Route plan
content:
application/json:
schema:
$ref: '#/components/schemas/RoutePlan'
/v1/stages/plan:
post:
summary: Split a route into daily stages
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/StagePlanRequest'
responses:
'200':
description: Stage plans
content:
application/json:
schema:
type: object
properties:
stages:
type: array
items:
$ref: '#/components/schemas/StagePlan'
/v1/routes/{routeId}/pois:
get:
summary: Get route-corridor POIs
parameters:
- in: path
name: routeId
required: true
schema: { type: string }
- in: query
name: category
schema: { $ref: '#/components/schemas/PoiCategory' }
- in: query
name: buffer_km
schema: { type: number, default: 5 }
responses:
'200':
description: POIs
content:
application/json:
schema:
type: object
properties:
pois:
type: array
items:
$ref: '#/components/schemas/Poi'
attribution:
type: array
items: { type: string }
/v1/routes/{routeId}/gaps:
get:
summary: Get critical service gaps
parameters:
- in: path
name: routeId
required: true
schema: { type: string }
responses:
'200':
description: Service gaps
content:
application/json:
schema:
type: object
properties:
gaps:
type: array
items:
$ref: '#/components/schemas/ServiceGap'
/v1/rules:
get:
summary: Get local rule cards
parameters:
- in: query
name: bbox
schema:
type: string
description: minLon,minLat,maxLon,maxLat
- in: query
name: route_id
schema: { type: string }
responses:
'200':
description: Rule cards
content:
application/json:
schema:
type: object
properties:
rules:
type: array
items:
$ref: '#/components/schemas/RuleCard'
disclaimer:
type: string
/v1/offline-packs:
post:
summary: Create offline pack manifest
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [tripId, routeId]
properties:
tripId: { type: string }
routeId: { type: string }
routeBufferKm: { type: number, default: 5 }
responses:
'200':
description: Offline pack manifest
content:
application/json:
schema:
$ref: '#/components/schemas/OfflinePackManifest'
/v1/routes/{routeId}/export:
get:
summary: Export route
parameters:
- in: path
name: routeId
required: true
schema: { type: string }
- in: query
name: format
required: true
schema:
type: string
enum: [gpx, tcx, fit]
responses:
'200':
description: Route export file
content:
application/gpx+xml:
schema: { type: string }
application/json:
schema: { type: object }
/v1/reports:
post:
summary: Submit local report
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LocalReportCreate'
responses:
'201':
description: Report submitted
content:
application/json:
schema:
$ref: '#/components/schemas/LocalReport'
components:
schemas:
Coordinate:
type: object
required: [lat, lon]
properties:
lat: { type: number }
lon: { type: number }
elevationM:
type: number
description: Optional elevation in meters above sea level when supplied by the active provider.
TripRequest:
type: object
required: [start, end, profile, sleepPreference, dailyDistanceKm]
properties:
start: { $ref: '#/components/schemas/Coordinate' }
end: { $ref: '#/components/schemas/Coordinate' }
viaPoints:
type: array
items: { $ref: '#/components/schemas/Coordinate' }
maxItems: 24
startDate: { type: string, format: date }
endDate: { type: string, format: date }
profile: { type: string }
sleepPreference: { type: string }
dailyDistanceKm:
type: object
required: [min, target, max]
properties:
min: { type: number }
target: { type: number }
max: { type: number }
waterGapMaxKm: { type: number }
foodGapMaxKm: { type: number }
Trip:
type: object
properties:
id: { type: string }
title: { type: string }
request: { $ref: '#/components/schemas/TripRequest' }
RoutePlanRequest:
type: object
required: [tripRequest]
properties:
tripRequest: { $ref: '#/components/schemas/TripRequest' }
provider: { type: string, default: mock }
RoutePlan:
type: object
properties:
id: { type: string }
tripId: { type: string }
geometry:
type: array
items: { $ref: '#/components/schemas/Coordinate' }
distanceM: { type: integer }
ascentM: { type: integer }
descentM: { type: integer }
provider: { type: string }
segments:
type: array
items: { $ref: '#/components/schemas/RouteSegment' }
surfaceBreakdown:
type: object
additionalProperties: { type: number }
suitabilityScore: { type: number }
warnings:
type: array
items: { $ref: '#/components/schemas/RouteWarning' }
attribution:
type: array
items: { type: string }
RouteSegment:
type: object
properties:
id: { type: string }
geometry:
type: array
items: { $ref: '#/components/schemas/Coordinate' }
distanceM: { type: integer }
startMeters: { type: integer }
endMeters: { type: integer }
ascentM: { type: integer }
descentM: { type: integer }
avgGradePercent: { type: number }
maxGradePercent: { type: number }
surface: { type: string }
smoothness: { type: string }
highway: { type: string }
bicycleAccess: { type: string }
legalAccessConfidence: { type: string }
trafficStress: { type: number }
officialCycleRoute: { type: boolean }
protectedAreaOverlap: { type: boolean }
sourceConfidence: { type: string }
StagePlanRequest:
type: object
required: [routeId, tripRequest]
properties:
routeId: { type: string }
tripRequest: { $ref: '#/components/schemas/TripRequest' }
StagePlan:
type: object
properties:
id: { type: string }
dayIndex: { type: integer }
startMeters: { type: integer }
endMeters: { type: integer }
distanceM: { type: integer }
ascentM: { type: integer }
descentM: { type: integer }
expectedRideTimeMinutes:
type: object
properties:
low: { type: integer }
high: { type: integer }
sleepCandidates:
type: array
items: { $ref: '#/components/schemas/Poi' }
waterPois:
type: array
items: { $ref: '#/components/schemas/Poi' }
foodPois:
type: array
items: { $ref: '#/components/schemas/Poi' }
repairPois:
type: array
items: { $ref: '#/components/schemas/Poi' }
bailoutPois:
type: array
items: { $ref: '#/components/schemas/Poi' }
warnings:
type: array
items: { $ref: '#/components/schemas/RouteWarning' }
planB:
type: object
properties:
earlierEndMeters: { type: integer }
laterEndMeters: { type: integer }
reason: { type: string }
PoiCategory:
type: string
enum: [water, food, sleep, repair, bailout, charging, emergency]
Poi:
type: object
properties:
id: { type: string }
category: { $ref: '#/components/schemas/PoiCategory' }
name: { type: string }
location: { $ref: '#/components/schemas/Coordinate' }
source: { type: string }
confidence: { type: string }
metersFromStart: { type: integer }
distanceFromRouteM: { type: integer }
detourDistanceM: { type: integer }
RouteWarning:
type: object
properties:
code: { type: string }
severity: { type: string, enum: [info, notice, warning, critical] }
title: { type: string }
message: { type: string }
metersFromStart: { type: integer }
segmentId: { type: string }
ServiceGap:
type: object
properties:
category: { $ref: '#/components/schemas/PoiCategory' }
startM: { type: integer }
endM: { type: integer }
distanceM: { type: integer }
severity: { type: string }
explanation: { type: string }
RuleCard:
type: object
properties:
id: { type: string }
ruleType: { type: string }
jurisdiction: { type: string }
status: { type: string }
confidence: { type: string }
summary: { type: string }
sourceUrl: { type: string }
lastReviewedAt: { type: string, format: date }
OfflinePackManifest:
type: object
properties:
packId: { type: string }
tripId: { type: string }
routeId: { type: string }
createdAt: { type: string, format: date-time }
expiresAt: { type: string, format: date-time }
bbox:
type: array
minItems: 4
maxItems: 4
items: { type: number }
routeBufferKm: { type: number }
includedLayers:
type: array
items: { type: string }
dataVersions: { type: object }
files:
type: array
items: { type: object }
warnings:
type: array
items: { $ref: '#/components/schemas/RouteWarning' }
LocalReportCreate:
type: object
required: [reportType, location, observedAt]
properties:
reportType: { type: string }
location: { $ref: '#/components/schemas/Coordinate' }
routeId: { type: string }
metersFromStart: { type: integer }
observedAt: { type: string, format: date-time }
details: { type: string }
payload: { type: object }
offlineClientId: { type: string }
LocalReport:
allOf:
- $ref: '#/components/schemas/LocalReportCreate'
- type: object
properties:
id: { type: string }
moderationStatus: { type: string }
trustScore: { type: number }
queuedOffline: { type: boolean }