This document summarizes the backend endpoints implemented in the current codebase.
- Local development:
http://localhost:3000/api - Production: use your deployed application domain and append
/api
Most protected endpoints require an authenticated NextAuth session cookie.
The authentication flow implemented by the app is:
POST /api/auth/signupPOST /api/auth/verify-otpPOST /api/auth/[...nextauth]for sign-in- Use the session cookie on later API requests
Create a new account and send a one-time OTP to the user's email.
Request body:
{
"name": "Asha Sharma",
"email": "asha@example.com",
"password": "securepassword"
}Typical responses:
200 OKwithok: true,userId, and a success message400 Bad Requestwhen the email already exists207 Multi-Statusif the account is created but the OTP email could not be sent
Verify the email with the 6-digit OTP.
Request body:
{
"email": "asha@example.com",
"otp": "123456"
}Generate and resend a fresh OTP for an unverified account.
Request body:
{
"email": "asha@example.com"
}Request a password reset email.
Request body:
{
"email": "asha@example.com"
}Reset the password using a valid reset token.
Request body:
{
"token": "<reset-token>",
"password": "newSecurePassword"
}Change the currently authenticated user's password.
Request body:
{
"currentPassword": "oldPassword",
"newPassword": "newStrongPassword"
}NextAuth-owned credential authentication route. This handles sign-in and callback operations.
Update profile fields for the current authenticated user.
Request body:
{
"name": "Updated Name",
"bio": "Travel enthusiast",
"location": "Delhi"
}Create a travel ticket submission for the current user.
Request body:
{
"destination": "Paris",
"departureDate": "2026-08-02",
"file": "<File object>"
}Notes:
- The route currently stores the ticket record in Prisma.
- The file upload itself is still a placeholder and is not yet persisted to a real object storage bucket.
Return the current user's tickets, ordered from newest to oldest.
All admin endpoints require the current user to have ADMIN role.
List tickets for admin review.
Optional query parameter:
status=VERIFIEDstatus=REJECTEDstatus=PENDING
Fetch a single ticket record for inspection.
Update a ticket status to VERIFIED or REJECTED.
Request body:
{
"status": "VERIFIED"
}List all route records owned by the authenticated user.
Create a new route, or update an existing route when the request includes an id.
Request body shape:
{
"id": "optional-existing-route-id",
"origin": { "lat": 28.6139, "lng": 77.2090 },
"destination": { "lat": 48.8566, "lng": 2.3522 },
"waypoints": [
{
"location": { "lat": 41.0082, "lng": 28.9784 },
"stopover": true,
"name": "Istanbul"
}
],
"originName": "New Delhi",
"destinationName": "Paris",
"distance": 12345,
"duration": 3600,
"encodedPolyline": "<polyline-string>",
"tripName": "Summer Trip",
"notes": "Optional notes"
}Fetch a single route belonging to the authenticated user.
Delete a saved route owned by the authenticated user.
Find verified travellers traveling to the same destination within a ±3 day date window.
Example:
GET /api/matches?destination=Paris&date=2026-08-02Response:
{
"matches": [],
"cached": false
}Return a page of the conversation transcript. The caller must be a participant,
otherwise the endpoint responds 404.
Query parameters:
| Name | Default | Notes |
|---|---|---|
conversationId |
— | Required. |
limit |
20 |
Capped at 100. |
cursor |
— | Opaque cursor from a previous pagination.nextCursor. |
Response:
{
"items": [{ "id": "msg-3", "text": "See you at the gate", "createdAt": "..." }],
"pagination": {
"limit": 20,
"nextCursor": "eyJ2ZXJzaW9uIjoxLCJ0aW1lc3RhbXAiOiIuLi4iLCJpZCI6Im1zZy0yIn0",
"hasMore": true
},
"messages": [{ "id": "msg-1", "text": "Landing at 6", "createdAt": "..." }]
}Two orderings are returned deliberately:
itemsis newest-first, matching the query order, sopagination.nextCursorlines up with the last element.messagesis the same page re-sorted oldest-first, which is the order a chat transcript is rendered in. Passpagination.nextCursorback ascursorto walk further into the past and prepend the result.
400 is returned for a malformed limit or cursor.
Send a message to a conversation the caller belongs to. Either text or
routeId must be present.
Request body:
{
"conversationId": "conv-1",
"text": "Booked the 7am bus",
"routeId": "route-1"
}A routeId must belong to the sender; otherwise the endpoint responds 403.
On success the created message is broadcast over Pusher to the conversation
channel and to each participant's personal channel.
List the caller's conversations, most recently updated first, each with the other participant and the latest message for the sidebar.
Send a natural-language message to the Gemini-based TravelBox AI assistant.
Request body:
{
"message": "How do I upload my ticket?"
}Response:
{
"reply": "You can upload your ticket from the dashboard..."
}Important:
- This endpoint requires
GEMINI_API_KEYto be configured. - It validates a short message payload and returns a single assistant reply.
These endpoints are the most important ones in the current app:
- Authentication and OTP-based signup
- Ticket upload and list retrieval
- Admin verification workflow
- Saved route CRUD
- Match discovery for verified travellers
- Gemini-powered chat assistance
If you are adding or changing endpoints, keep this document updated so the README and backend behavior stay aligned.