Ride API
All endpoints require a Firebase ID token in the Authorization: Bearer <token>
header. A missing or invalid token returns 401 UNAUTHORIZED.
Get Ride
GET /rides/{rideId}
Auth: Bearer token (Firebase ID token)
Response 200
{
"id": "string",
"creatorId": "string",
"adminIds": ["string"],
"groupId": "string | null",
"type": "private | public",
"title": "string",
"description": "string",
"startAt": "string", // ISO 8601
"endAt": "string", // ISO 8601
"posterUrl": "string | null",
"settings": {
"requireRsvpApproval": true,
"maxRiders": 25,
},
"startLocation": {
"id": "string",
"placeId": "string | null",
"latitude": 12.9716,
"longitude": 77.5946,
"title": "string",
"type": "origin",
},
"endLocation": {
"id": "string",
"placeId": "string | null",
"latitude": 15.3647,
"longitude": 75.1240,
"title": "string",
"type": "destination",
},
"breakpointsTo": [
{
"id": "string",
"placeId": "string | null",
"latitude": 13.9299,
"longitude": 75.5681,
"title": "string",
"type": "haltPoint",
},
],
"createdAt": "string", // ISO 8601
"updatedAt": "string", // ISO 8601
}
Errors
| Status | Code | Condition |
|---|---|---|
| 401 | UNAUTHORIZED |
No valid Firebase ID token |
| 403 | NOT_GROUP_MEMBER |
Ride is a group ride and caller is not a member of that group |
| 404 | NOT_FOUND |
Ride does not exist |
Create Ride
POST /rides
Auth: Bearer token (Firebase ID token)
Request
{
"type": "private | public", // required
"title": "string", // required
"description": "string", // optional
"startAt": "string", // required, ISO 8601
"endAt": "string", // required, ISO 8601
"groupId": "string", // optional; include to create a group ride
"posterUrl": "string", // optional
"settings": {
"requireRsvpApproval": false, // required
"maxRiders": 25, // required; 0 = unlimited
},
"startLocation": {
"id": "string",
"placeId": "string | null",
"latitude": 12.9716,
"longitude": 77.5946,
"title": "string",
"type": "origin",
},
"endLocation": {
"id": "string",
"placeId": "string | null",
"latitude": 15.3647,
"longitude": 75.1240,
"title": "string",
"type": "destination",
},
"breakpointsTo": [], // optional; max 6 items
}
Response 201
{ "id": "string" } // newly created ride ID
Errors
| Status | Code | Condition |
|---|---|---|
| 400 | MISSING_FIELD |
type, title, startAt, endAt, startLocation, or endLocation not provided |
| 400 | INVALID_FIELD |
breakpointsTo exceeds 6 items, or startAt is not before endAt |
| 401 | UNAUTHORIZED |
No valid Firebase ID token |
| 403 | SUBSCRIPTION_LIMIT_REACHED |
Caller has reached the maximum ride count for their subscription |
| 403 | NOT_GROUP_MEMBER |
groupId provided but caller is not a member of that group |
Update Ride
PATCH /rides/{rideId}
Auth: Bearer token (Firebase ID token)
All fields optional; only provided fields are updated.
Server-controlled fields — never accepted: id, creatorId, adminIds,
status, deletedAt, createdAt, updatedAt. Sending any of these in the
request body is an error. Ride lifecycle transitions (status changes) use
dedicated endpoints; deletion requires DELETE /rides/{rideId} (creator only).
Request
{
"title": "string",
"description": "string",
"startAt": "string", // ISO 8601
"endAt": "string", // ISO 8601
"posterUrl": "string | null",
"settings": {
"requireRsvpApproval": true,
"maxRiders": 30,
},
"startLocation": {/* Location */},
"endLocation": {/* Location */},
"breakpointsTo": [],
}
Response 200
{ "id": "string" }
Errors
| Status | Code | Condition |
|---|---|---|
| 400 | MISSING_FIELD |
Partial update removes a required field |
| 400 | INVALID_FIELD |
breakpointsTo exceeds 6 items, or startAt is not before endAt |
| 400 | RIDE_ALREADY_STARTED |
Ride start time has passed; edits are no longer allowed |
| 401 | UNAUTHORIZED |
No valid Firebase ID token |
| 403 | FORBIDDEN |
Caller is not the ride creator or an admin |
| 404 | NOT_FOUND |
Ride does not exist |
Delete Ride
DELETE /rides/{rideId}
Auth: Bearer token (Firebase ID token)
Request
{ "confirmation": "DELETE" } // required; must be the exact string "DELETE"
Response 204 — no body
Errors
| Status | Code | Condition |
|---|---|---|
| 400 | MISSING_FIELD |
confirmation not provided |
| 400 | INVALID_CONFIRMATION |
confirmation is not exactly "DELETE" |
| 401 | UNAUTHORIZED |
No valid Firebase ID token |
| 403 | FORBIDDEN |
Caller is not the ride creator |
| 404 | NOT_FOUND |
Ride does not exist |
RSVP to Ride
POST /rides/{rideId}/rsvp
Auth: Bearer token (Firebase ID token)
Request
{
"status": "yes | no | maybe", // required
"joiningLocationId": "string", // required when status is "yes" or "maybe"
}
Response 200
{
"status": "yes | no | maybe | pending",
// "pending" when requireRsvpApproval is true and status was "yes" or "maybe"
}
Errors
| Status | Code | Condition |
|---|---|---|
| 400 | MISSING_FIELD |
status not provided, or joiningLocationId missing for yes/maybe |
| 400 | INVALID_FIELD |
joiningLocationId does not match any location on the ride |
| 401 | UNAUTHORIZED |
No valid Firebase ID token |
| 403 | NOT_GROUP_MEMBER |
Ride is a group ride and caller is not a member |
| 403 | RIDE_FULL |
maxRiders limit reached |
| 404 | NOT_FOUND |
Ride does not exist |
Get Ride Location
GET /rides/{rideId}/location
Auth: Bearer token (Firebase ID token)
Returns the current GPS positions of all other participants with yes or
maybe status. The caller's own position is never included.
Response 200
{
"locations": [
{
"userId": "string",
"latitude": 12.9716,
"longitude": 77.5946,
"updatedAt": "string", // ISO 8601; stale if not recently refreshed
},
],
}
Errors
| Status | Code | Condition |
|---|---|---|
| 401 | UNAUTHORIZED |
No valid Firebase ID token |
| 403 | FORBIDDEN |
Caller's RSVP status is no or caller has no RSVP on this ride |
| 404 | NOT_FOUND |
Ride does not exist |