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