🏡 TripNest API

Event Booking & Review Management API Documentation

📖 Overview

The TripNest API provides endpoints for managing events, bookings, and reviews. Built with Express.js and TypeScript.

Base URL

https://naylinhtet.me/api

Response Format

All responses are returned in JSON format.

{
  "data": { ... },
  "message": "Success message"
}

Error Response

{
  "error": "Error description"
}

🔐 Authentication

Protected endpoints require a JWT token in the Authorization header.

💡 Tip: After login or registration, store the returned token and include it in all subsequent requests to protected endpoints.

Authorization Header

Authorization: Bearer <your-jwt-token>

Token Expiration

Tokens expire after 24 hours. After expiration, users must login again.

👤 Auth Endpoints

POST /api/auth/register Create a new user account

Request Body

Field Type Required Description
email string Yes User's email address
password string Yes User's password
name string No User's display name

Example Request

{
  "email": "user@example.com",
  "password": "securePassword123",
  "name": "John Doe"
}

Success Response (201)

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "userId": "clx1234567890",
  "email": "user@example.com",
  "expiresIn": "24h",
  "message": "Registration successful"
}

Error Responses

// 400 Bad Request
{ "error": "Missing required fields: email, password" }

// 409 Conflict
{ "error": "User with this email already exists" }
POST /api/auth/login Authenticate and get token

Request Body

Field Type Required Description
email string Yes User's email address
password string Yes User's password

Example Request

{
  "email": "user@example.com",
  "password": "securePassword123"
}

Success Response (200)

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "userId": "clx1234567890",
  "email": "user@example.com",
  "expiresIn": "24h",
  "message": "Login successful"
}

Error Responses

// 401 Unauthorized
{ "error": "Invalid email or password" }
POST /api/auth/logout Invalidate current token

Headers

Authorization: Bearer <your-jwt-token>

Success Response (200)

{ "message": "Logout successful" }
POST /api/auth/change-password Change user's password Auth

Description

Changes the authenticated user's password. Requires the current password for verification.

Headers

Authorization: Bearer <your-jwt-token>

Request Body

Field Type Required Description
oldPassword string Yes Current password
newPassword string Yes New password

Example Request

{
  "oldPassword": "currentPassword123",
  "newPassword": "newSecurePassword456"
}

Success Response (200)

{
  "message": "Password changed successfully"
}

Error Responses

// 400 Bad Request
{ "error": "Missing required fields: oldPassword, newPassword" }

// 401 Unauthorized
{ "error": "Unauthorized" }
{ "error": "Old password is incorrect" }
POST /api/auth/forgot-password Request password reset email

Description

Sends a password reset link to the user's email address. For security, always returns a success message even if the email doesn't exist.

Request Body

Field Type Required Description
email string Yes User's registered email address

Example Request

{
  "email": "user@example.com"
}

Success Response (200)

{
  "message": "If this email exists, a reset link has been sent"
}
POST /api/auth/reset-password Reset password with token

Description

Resets the user's password using the token received via email. Token expires after 1 hour and can only be used once.

Request Body

Field Type Required Description
resetToken string Yes Token received from password reset email
newPassword string Yes New password (minimum 6 characters)

Example Request

{
  "resetToken": "a1b2c3d4e5f6...",
  "newPassword": "newSecurePassword123"
}

Success Response (200)

{
  "message": "Password reset successfully"
}

Error Responses

// 400 Bad Request
{ "error": "Missing required fields: resetToken, newPassword" }
{ "error": "Password must be at least 6 characters" }
{ "error": "Invalid or expired reset token" }

📅 Events Endpoints

Events are public resources - no authentication required for viewing.

GET /api/events Get all events

Success Response (200)

[
  {
    "id": "clx1234567890",
    "title": "Summer Music Festival",
    "description": "A three-day music festival",
    "date": "2026-07-15T18:00:00.000Z",
    "images": [
      {
        "id": "img123",
        "eventId": "clx1234567890",
        "imageUrl": "https://res.cloudinary.com/tripnest/events/banner.jpg",
        "createdAt": "2026-01-20T10:00:00.000Z"
      }
    ],
    "location": "Central Park, NYC",
    "capacity": 5000,
    "price": 99.99,
    "createdAt": "2026-01-20T10:00:00.000Z"
  }
]
GET /api/events/upcoming Get upcoming events only

Description

Returns events with dates in the future, sorted by date ascending.

Success Response (200)

[
  {
    "id": "clx1234567890",
    "title": "Summer Music Festival",
    "description": "A three-day music festival",
    "date": "2026-07-15T18:00:00.000Z",
    "images": [
      {
        "id": "img123",
        "eventId": "clx1234567890",
        "imageUrl": "https://res.cloudinary.com/tripnest/events/banner.jpg",
        "createdAt": "2026-01-20T10:00:00.000Z"
      }
    ],
    "location": "Central Park, NYC",
    "capacity": 5000,
    "price": 99.99,
    "createdAt": "2026-01-20T10:00:00.000Z"
  }
]
GET /api/events/tickets/availability Get events arranged by available tickets and fully booked events

Description

Returns events arranged by available tickets (from smallest to greatest) and a separate list of fully booked events. Useful for displaying events by availability status.

Success Response (200)

{
  "eventsSortedByAvailability": [
    {
      "id": "clx1234567890",
      "title": "Jazz Night",
      "description": "Evening jazz performance",
      "date": "2026-03-15T19:00:00.000Z",
      "images": [],
      "location": "Blue Note, NYC",
      "capacity": 100,
      "price": 75.00,
      "mood": "relaxed",
      "organizerId": "org123",
      "createdAt": "2026-01-20T10:00:00.000Z",
      "bookedTickets": 95,
      "availableTickets": 5
    },
    {
      "id": "clx9876543210",
      "title": "Summer Music Festival",
      "description": "A three-day music festival",
      "date": "2026-07-15T18:00:00.000Z",
      "images": [],
      "location": "Central Park, NYC",
      "capacity": 5000,
      "price": 99.99,
      "mood": "festive",
      "organizerId": "org456",
      "createdAt": "2026-01-20T10:00:00.000Z",
      "bookedTickets": 2000,
      "availableTickets": 3000
    }
  ],
  "fullyBookedEvents": [
    {
      "id": "clx5555555555",
      "title": "VIP Concert Experience",
      "description": "Exclusive concert for members",
      "date": "2026-02-28T20:00:00.000Z",
      "images": [],
      "location": "Madison Square Garden, NYC",
      "capacity": 500,
      "price": 150.00,
      "mood": "exclusive",
      "organizerId": "org789",
      "createdAt": "2026-01-15T10:00:00.000Z"
    }
  ]
}

Response Fields

Field Type Description
eventsSortedByAvailability array Events with available tickets, sorted by available count (ascending)
eventsSortedByAvailability[].bookedTickets number Number of confirmed bookings for the event
eventsSortedByAvailability[].availableTickets number Number of available tickets (capacity - bookedTickets)
fullyBookedEvents array Events that have no available tickets (fully booked)

Examples

GET /api/events/tickets/availability
GET /api/events/search?location=NYC&mood=chill Search events by location, keyword, or mood

Query Parameters

Parameter Type Required Description
location string No Location to search for
keyword string No Matches event title or description
mood string No Matches event mood

Examples

GET /api/events/search?location=New%20York
GET /api/events/search?keyword=music
GET /api/events/search?mood=chill
GET /api/events/search?location=New%20York&keyword=music
GET /api/events/search?location=New%20York&mood=chill
GET /api/events/:id Get event by ID

Path Parameters

Parameter Type Description
id string Event ID

Success Response (200)

{
  "id": "event-uuid",
  "title": "Sunset Beach Party",
  "description": "Join us for an amazing beach party experience",
  "date": "2024-07-15T18:00:00.000Z",
  "location": "Malibu Beach, CA",
  "capacity": 200,
  "price": 49.99,
  "mood": "festive",
  "organizerId": "organizer-uuid",
  "createdAt": "2024-01-15T10:30:00.000Z",
  "images": [
    {
      "id": "image-uuid-1",
      "imageUrl": "https://res.cloudinary.com/..."
    },
    {
      "id": "image-uuid-2",
      "imageUrl": "https://res.cloudinary.com/..."
    }
  ]
}

Error Response (404)

{ "error": "Event not found" }
POST /api/events Create a new event Auth

Headers

Authorization: Bearer <your-jwt-token>
🔒 Organizer Required: You must have an organizer profile to create events. Use /api/organizers to create one.

Request Body

Field Type Required Description
title string Yes Event title
description string No Event description
date string (ISO) Yes Event date/time
location string Yes Event location
capacity number Yes Max attendees
price number Yes Ticket price
mood string No Event mood or theme
imageUrls string[] No Image URLs for the event (max 5)

Example Request (JSON)

{
  "title": "Summer Music Festival",
  "description": "A three-day music festival featuring top artists",
  "date": "2026-07-15T18:00:00.000Z",
  "location": "Central Park, NYC",
  "capacity": 5000,
  "price": 99.99,
  "mood": "vibrant",
  "imageUrls": [
    "https://res.cloudinary.com/tripnest/events/banner.jpg"
  ]
}

Success Response (201)

{
  "id": "clx1234567890",
  "title": "Summer Music Festival",
  "description": "A three-day music festival featuring top artists",
  "date": "2026-07-15T18:00:00.000Z",
  "images": [
    {
      "id": "img123",
      "eventId": "clx1234567890",
      "imageUrl": "https://res.cloudinary.com/tripnest/events/banner.jpg",
      "createdAt": "2026-01-20T10:00:00.000Z"
    }
  ],
  "location": "Central Park, NYC",
  "capacity": 5000,
  "price": 99.99,
  "mood": "vibrant",
  "organizerId": "org123456",
  "createdAt": "2026-01-20T10:00:00.000Z"
}
PATCH /api/events/:id Update an event Auth

Headers

Authorization: Bearer <your-jwt-token>

Request Body

Include only fields you want to update:

{
  "title": "Updated Event Title",
  "price": 149.99
}
DELETE /api/events/:id Delete an event Auth

Headers

Authorization: Bearer <your-jwt-token>

Success Response (200)

{ "message": "Event deleted successfully" }

📊 Dashboard Endpoints

🔒 Authentication Required: All dashboard endpoints require a valid JWT token and an organizer profile.
GET /api/dashboard/summary Organizer dashboard summary Auth

Headers

Authorization: Bearer <your-jwt-token>

Success Response (200)

{
  "organizer": {
    "id": "org123456",
    "userId": "user123",
    "organizationName": "TripNest Org",
    "contactNumber": "123-456-7890",
    "address": "Downtown"
  },
  "bookingStatus": {
    "PENDING": 2,
    "CONFIRMED": 5,
    "CANCELLED": 1
  },
  "events": [
    {
      "eventId": "evt123",
      "title": "Summer Music Festival",
      "images": [
        {
          "id": "img123",
          "imageUrl": "https://res.cloudinary.com/tripnest/events/banner.jpg"
        },
        {
          "id": "img124",
          "imageUrl": "https://res.cloudinary.com/tripnest/events/poster.jpg"
        }
      ],
      "totalRevenue": 499.95,
      "totalBookings": 5,
      "totalTickets": 5
    }
  ],
  "totalRevenue": 499.95,
  "totalBookings": 8,
  "totalTickets": 10
}
GET /api/dashboard/events Event revenue breakdown Auth

Headers

Authorization: Bearer <your-jwt-token>

Success Response (200)

{
  "organizer": {
    "id": "org123456",
    "userId": "user123",
    "organizationName": "TripNest Org",
    "contactNumber": "123-456-7890",
    "address": "Downtown"
  },
  "events": [
    {
      "eventId": "evt123",
      "title": "Summer Music Festival",
      "images": [
        {
          "id": "img123",
          "imageUrl": "https://res.cloudinary.com/tripnest/events/banner.jpg"
        },
        {
          "id": "img124",
          "imageUrl": "https://res.cloudinary.com/tripnest/events/poster.jpg"
        }
      ],
      "totalRevenue": 499.95,
      "totalBookings": 5,
      "totalTickets": 5
    }
  ]
}
GET /api/dashboard/revenue Revenue totals Auth

Headers

Authorization: Bearer <your-jwt-token>

Success Response (200)

{
  "organizer": {
    "id": "org123456",
    "userId": "user123",
    "organizationName": "TripNest Org",
    "contactNumber": "123-456-7890",
    "address": "Downtown"
  },
  "totalRevenue": 499.95,
  "totalBookings": 8,
  "totalTickets": 10
}

🎫 Bookings Endpoints

🔒 Authentication Required: All booking endpoints require a valid JWT token.
GET /api/bookings/me Get current user's bookings Auth

Description

Returns all bookings for the authenticated user.

Success Response (200)

[
  {
    "id": "clx1234567890",
    "userId": "clx0987654321",
    "eventId": "clx1111111111",
    "ticketCounts": 2,
    "status": "PENDING"
  },
  {
    "id": "clx0987654322",
    "userId": "clx0987654321",
    "eventId": "clx2222222222",
    "ticketCounts": 1,
    "status": "CONFIRMED"
  }
]
GET /api/bookings/:id Get booking by ID Auth

Path Parameters

Parameter Type Description
id string Booking ID

Success Response (200)

{
  "id": "clx1234567890",
  "userId": "clx0987654321",
  "eventId": "clx1111111111",
  "ticketCount": 2,
  "totalPrice": 199.98,
  "status": "CONFIRMED",
  "createdAt": "2026-01-25T10:00:00.000Z",
  "updatedAt": "2026-01-25T10:00:00.000Z"
}
POST /api/bookings Create a new booking Auth

Request Body

Field Type Required Description
eventId string Yes Event to book
ticketCounts number Yes Number of tickets

Example Request

{
  "eventId": "clx1111111111",
  "ticketCounts": 2
}

Success Response (201)

{
  "booking": {
    "id": "clx1234567890",
    "userId": "clx0987654321",
    "eventId": "clx1111111111",
    "ticketCounts": 2,
    "totalPrice": 199.98,
    "status": "PENDING"
  },
  "chatRoomId": "clxroom123456"
}
PATCH /api/bookings/:id/confirm Confirm a booking Auth

Description

Changes booking status from PENDING to CONFIRMED.

Success Response (200)

{
  "id": "clx1234567890",
  "status": "CONFIRMED",
  ...
}
PATCH /api/bookings/:id/cancel Cancel a booking Auth

Description

Changes booking status to CANCELLED.

Success Response (200)

{
  "id": "clx1234567890",
  "status": "CANCELLED",
  ...
}
PATCH /api/bookings/:id Update ticket count Auth

Request Body

{
  "ticketCounts": 4
}

⭐ Reviews Endpoints

Some review endpoints are public, others require authentication.

GET /api/reviews/event/:eventId Get reviews for an event Auth

Success Response (200)

[
  {
    "id": "clx1234567890",
    "eventId": "clx1111111111",
    "userId": "clx0987654321",
    "rating": 5,
    "comment": "Amazing event! Highly recommended.",
    "sentimentLabel": "POSITIVE",
    "sentimentScore": 0.95,
    "createdAt": "2026-01-25T10:00:00.000Z"
  }
]
GET /api/reviews/event/:eventId/rating Get average rating for event Auth

Success Response (200)

{
  "eventId": "clx1111111111",
  "averageRating": 4.5
}
GET /api/reviews/my Get current user's reviews Auth

Description

Returns all reviews created by the authenticated user.

GET /api/reviews/:id Get review by ID Auth

Error Response (404)

{ "error": "Review not found" }
POST /api/reviews Create a new review Auth

Request Body

Field Type Required Description
eventId string Yes Event to review
rating number Yes Rating (1-5)
comment string No Review text

Example Request

{
  "eventId": "clx1111111111",
  "rating": 5,
  "comment": "Amazing event! The atmosphere was incredible."
}
🧠 AI Sentiment Analysis: When you submit a review with a comment, the system automatically analyzes the sentiment using AI. The sentiment label (POSITIVE/NEGATIVE/NEUTRAL) and score will be added to the review.

Success Response (201)

{
  "id": "clx1234567890",
  "eventId": "clx1111111111",
  "userId": "clx0987654321",
  "rating": 5,
  "comment": "Amazing event! The atmosphere was incredible.",
  "sentimentStatus": "PENDING",
  "createdAt": "2026-01-25T10:00:00.000Z"
}

Error Response (409)

{ "error": "You have already reviewed this event" }
PATCH /api/reviews/:id Update your review Auth

Request Body

{
  "rating": 4,
  "comment": "Updated review text"
}

Error Response (403)

{ "error": "You can only update your own reviews" }
DELETE /api/reviews/:id Delete your review Auth

Success Response (200)

{ "message": "Review deleted successfully" }

Error Response (403)

{ "error": "You can only delete your own reviews" }

🧠 Sentiment Analysis Endpoints

🔒 Authentication Required: All sentiment endpoints require a valid JWT token.
How it works: When a review is created, a background job is queued for sentiment analysis using the AI API configured in AI_API. You can also trigger analysis manually via the POST endpoint below.
POST /api/sentiment/review/:reviewId Analyze sentiment for a review Auth

Success Response (200)

{
  "reviewId": "clx1234567890",
  "sentiment": {
    "label": "POSITIVE",
    "score": 0.95,
    "class": 1
  }
}

Sentiment Labels

Label Score Range Description
POSITIVE 0.2 to 1.0 Positive sentiment detected
NEUTRAL -0.2 to 0.2 Neutral or mixed sentiment
NEGATIVE -1.0 to -0.2 Negative sentiment detected
GET /api/sentiment/organizer/events/:eventId/summary Get sentiment summary for an event Auth

Success Response (200)

{
  "eventId": "clxevent123",
  "totalReviews": 12,
  "analyzedCount": 10,
  "positiveCount": 7,
  "negativeCount": 2,
  "neutralCount": 1,
  "averageScore": 0.58
}
GET /api/sentiment/organizer/events/:eventId/reviews List sentiment results for an event Auth

Success Response (200)

{
  "eventId": "clxevent123",
  "sentiments": [
    {
      "reviewId": "clxreview1",
      "label": "POSITIVE",
      "score": 0.93,
      "class": 1,
      "negativeSummary": "No negative reviews to summarize."
    },
    {
      "reviewId": "clxreview2",
      "label": "NEGATIVE",
      "score": -0.62,
      "class": -1,
      "negativeSummary": "Some customers reported service delays."
    }
  ]
}

👤 User Profile Endpoints

🔒 Authentication Required: All profile endpoints require a valid JWT token in the Authorization header.

GET /api/profile/me Get current user's profile Auth

Description

Returns the profile for the authenticated user. Returns default profile with placeholder values if no profile exists yet.

Headers

Authorization: Bearer <your-jwt-token>

Success Response (200)

{
  "id": "clx1234567890",
  "userId": "clx0987654321",
  "email": "user@example.com",
  "fullName": "John Doe",
  "phone": "+1234567890",
  "dateOfBirth": "1990-01-15T00:00:00.000Z",
  "gender": "Male",
  "profilePictureUrl": "https://res.cloudinary.com/tripnest/profiles/image.jpg"
}

Default Response (no profile yet)

{
  "id": null,
  "userId": "clx0987654321",
  "email": "user@example.com",
  "fullName": "Not Set",
  "phone": "Not Set",
  "dateOfBirth": null,
  "gender": "Not Set",
  "profilePictureUrl": "https://via.placeholder.com/200?text=Profile+Picture"
}
GET /api/profile/:id Get profile by ID Auth

Description

Retrieve a specific profile by its ID.

Headers

Authorization: Bearer <your-jwt-token>

Path Parameters

Parameter Type Required Description
id string Yes Profile ID

Success Response (200)

{
  "id": "clx1234567890",
  "userId": "clx0987654321",
  "email": "user@example.com",
  "fullName": "John Doe",
  "phone": "+1234567890",
  "dateOfBirth": "1990-01-15T00:00:00.000Z",
  "gender": "Male",
  "profilePictureUrl": "https://res.cloudinary.com/tripnest/profiles/image.jpg"
}

Error Responses

// 404 Not Found
{ "error": "Profile not found" }
POST /api/profile Create a new profile Auth

Description

Create a new profile for the authenticated user. Supports multipart/form-data for profile picture upload.

Headers

Authorization: Bearer <your-jwt-token>
Content-Type: multipart/form-data

Request Body (multipart/form-data)

Field Type Required Description
fullName string No User's full name
phone string No User's phone number
dateOfBirth string No Date of birth (ISO 8601, e.g. 1990-01-15)
gender string No User's gender
profilePicture file No Profile image file (max 5MB)

Example Request

{
  "fullName": "John Doe",
  "phone": "+1234567890",
  "dateOfBirth": "1990-01-15",
  "gender": "Male"
}

Success Response (201)

{
  "id": "clx1234567890",
  "userId": "clx0987654321",
  "email": "user@example.com",
  "fullName": "John Doe",
  "phone": "+1234567890",
  "dateOfBirth": "1990-01-15T00:00:00.000Z",
  "gender": "Male",
  "profilePictureUrl": "https://res.cloudinary.com/tripnest/profiles/image.jpg"
}

Error Responses

// 400 Bad Request
{ "error": "Profile already exists for this user" }

// 401 Unauthorized
{ "error": "Unauthorized" }
PATCH /api/profile/:id Update profile by ID Auth

Description

Update an existing profile with new information and/or profile picture.

Headers

Authorization: Bearer <your-jwt-token>
Content-Type: multipart/form-data

Path Parameters

Parameter Type Required Description
id string Yes Profile ID

Request Body (multipart/form-data)

Field Type Required Description
fullName string No Updated full name
phone string No Updated phone number
dateOfBirth string No Updated date of birth (ISO 8601)
gender string No Updated gender
profilePicture file No New profile image (max 5MB)

Example Request

{
  "phone": "+9876543210",
  "dateOfBirth": "1992-05-20"
}

Success Response (200)

{
  "id": "clx1234567890",
  "userId": "clx0987654321",
  "email": "user@example.com",
  "fullName": "John Doe",
  "phone": "+9876543210",
  "dateOfBirth": "1992-05-20T00:00:00.000Z",
  "gender": "Male",
  "profilePictureUrl": "https://res.cloudinary.com/tripnest/profiles/image.jpg"
}

Error Responses

// 404 Not Found
{ "error": "Profile not found" }
PATCH /api/profile/me Update current user's profile Auth

Description

Update the authenticated user's profile. Creates a new profile if one doesn't exist yet.

Headers

Authorization: Bearer <your-jwt-token>
Content-Type: multipart/form-data

Request Body (multipart/form-data)

Field Type Required Description
fullName string No Updated full name
phone string No Updated phone number
dateOfBirth string No Updated date of birth (ISO 8601)
gender string No Updated gender
profilePicture file No New profile image (max 5MB)

Example Request

{
  "fullName": "Jane Doe",
  "dateOfBirth": "1990-01-15",
  "gender": "Female"
}

Success Response (200)

{
  "id": "clx1234567890",
  "userId": "clx0987654321",
  "email": "jane@example.com",
  "fullName": "Jane Doe",
  "phone": "+1234567890",
  "dateOfBirth": "1990-01-15T00:00:00.000Z",
  "gender": "Female",
  "profilePictureUrl": "https://res.cloudinary.com/tripnest/profiles/profile.jpg"
}
DELETE /api/profile/:id Delete profile Auth

Description

Delete a profile by its ID.

Headers

Authorization: Bearer <your-jwt-token>

Path Parameters

Parameter Type Required Description
id string Yes Profile ID

Success Response (200)

{ "message": "Profile deleted successfully" }

Error Responses

// 404 Not Found
{ "error": "Profile not found" }

📸 Profile Picture Upload

Profile pictures are automatically uploaded to Cloudinary when provided.

🏢 Organizer Endpoints

🔒 Authentication Required: All organizer endpoints require a valid JWT token in the Authorization header.

GET /api/organizers/me Get current organizer profile Auth

Headers

Authorization: Bearer <your-jwt-token>

Success Response (200)

{
  "id": "org123456",
  "userId": "user123",
  "organizationName": "TripNest Org",
  "contactNumber": "123-456-7890",
  "address": "Downtown"
}

Default Response (no profile yet)

{
  "id": null,
  "userId": "user123",
  "organizationName": "Not Set",
  "contactNumber": "Not Set",
  "address": "Not Set"
}
GET /api/organizers/:id Get organizer profile by ID Auth

Headers

Authorization: Bearer <your-jwt-token>

Path Parameters

Parameter Type Required Description
id string Yes Organizer profile ID

Success Response (200)

{
  "id": "org123456",
  "userId": "user123",
  "organizationName": "TripNest Org",
  "contactNumber": "123-456-7890",
  "address": "Downtown"
}

Error Response (404)

{ "error": "Profile not found" }
POST /api/organizers Create organizer profile Auth

Headers

Authorization: Bearer <your-jwt-token>

Request Body

Field Type Required Description
organizationName string No Organization name
contactNumber string No Contact number
address string No Business address

Example Request

{
  "organizationName": "TripNest Org",
  "contactNumber": "123-456-7890",
  "address": "Downtown"
}

Success Response (201)

{
  "id": "org123456",
  "userId": "user123",
  "organizationName": "TripNest Org",
  "contactNumber": "123-456-7890",
  "address": "Downtown"
}
PATCH /api/organizers/me Update current organizer profile Auth

Headers

Authorization: Bearer <your-jwt-token>

Request Body

Include only fields you want to update:

{
  "organizationName": "Updated Org",
  "contactNumber": "123-456-0000"
}

Success Response (200)

{
  "id": "org123456",
  "userId": "user123",
  "organizationName": "Updated Org",
  "contactNumber": "123-456-0000",
  "address": "Downtown"
}
PATCH /api/organizers/:id Update organizer profile by ID Auth

Headers

Authorization: Bearer <your-jwt-token>

Request Body

Include only fields you want to update:

{
  "address": "Uptown"
}
DELETE /api/organizers/:id Delete organizer profile Auth

Headers

Authorization: Bearer <your-jwt-token>

Success Response (200)

{ "message": "Profile deleted successfully" }

Error Response (404)

{ "error": "Profile not found" }

💬 Chat

Chat rooms allow users with bookings to communicate with other attendees of the same event.

💡 Note: Users with bookings can access the event chat room. Chat rooms now include the event's first image in responses.
GET /api/chat/rooms Get all chat rooms user is a member of 🔒 Auth

Headers

Header Value Required
Authorization Bearer <token> Yes

Success Response (200)

{
  "rooms": [
    {
      "id": "room-uuid",
    "createdAt": "2026-02-07T10:00:00.000Z",
    "eventTitle": "Beach Party 2026",
    "eventImageUrl": "https://res.cloudinary.com/tripnest/events/cover.jpg"
    "eventTitle": "Beach Party 2026",
    "eventImageUrl": "https://res.cloudinary.com/tripnest/events/cover.jpg"
      "createdAt": "2026-02-07T10:00:00.000Z",
      "eventTitle": "Beach Party 2026",
      "eventImageUrl": "https://res.cloudinary.com/tripnest/events/cover.jpg",
      "memberCount": 15,
      "lastMessage": {
        "id": "msg-uuid",
        "senderId": "user-uuid",
        "senderName": "John Doe",
        "senderEmail": "john@example.com",
        "content": "See you all there!",
        "createdAt": "2026-02-07T12:30:00.000Z"
      }
    }
  ]
}
POST /api/chat/events/:eventId/join Join or create chat room for an event 🔒 Auth

Headers

Header Value Required
Authorization Bearer <token> Yes

Path Parameters

Parameter Type Required Description
eventId string Yes Event ID to join chat for

Success Response (200)

{
  "message": "Successfully joined chat room",
  "room": {
    "id": "room-uuid",
    "eventId": "event-uuid",
    "createdAt": "2026-02-07T10:00:00.000Z"
  }
}

Error Responses

// 403 Forbidden - No confirmed booking
{ "error": "You must have a confirmed booking to access the chat room" }
GET /api/chat/rooms/:roomId Get chat room details 🔒 Auth

Headers

Header Value Required
Authorization Bearer <token> Yes

Path Parameters

Parameter Type Required Description
roomId string Yes Chat room ID

Success Response (200)

{
  "room": {
    "id": "room-uuid",
    "eventId": "event-uuid",
    "createdAt": "2026-02-07T10:00:00.000Z"
  }
}

Error Responses

// 403 Forbidden
{ "error": "You are not a member of this chat room" }

// 404 Not Found
{ "error": "Chat room not found" }
GET /api/chat/rooms/:roomId/members Get chat room members 🔒 Auth

Headers

Header Value Required
Authorization Bearer <token> Yes

Path Parameters

Parameter Type Required Description
roomId string Yes Chat room ID

Success Response (200)

{
  "members": [
    {
      "id": "member-uuid",
      "userId": "user-uuid",
      "userName": "John Doe",
      "userEmail": "john@example.com",
      "joinedAt": "2026-02-07T10:00:00.000Z"
    }
  ]
}

Error Responses

// 403 Forbidden
{ "error": "You are not a member of this chat room" }
GET /api/chat/rooms/:roomId/messages Get chat room messages with pagination 🔒 Auth

Headers

Header Value Required
Authorization Bearer <token> Yes

Path Parameters

Parameter Type Required Description
roomId string Yes Chat room ID

Query Parameters

Parameter Type Required Description
limit number No Number of messages to return (default: 50, max: 100)
before string No ISO date string - get messages before this timestamp

Example Request

GET /api/chat/rooms/room-uuid/messages?limit=20&before=2026-02-07T12:00:00.000Z

Success Response (200)

{
  "messages": [
    {
      "id": "msg-uuid",
      "senderId": "user-uuid",
      "senderName": "John Doe",
      "senderEmail": "john@example.com",
      "content": "Hello everyone!",
      "createdAt": "2026-02-07T10:30:00.000Z"
    },
    {
      "id": "msg-uuid-2",
      "senderId": "user-uuid-2",
      "senderName": "Jane Smith",
      "senderEmail": "jane@example.com",
      "content": "Hi! Excited for the event!",
      "createdAt": "2026-02-07T10:35:00.000Z"
    }
  ]
}

Error Responses

// 403 Forbidden
{ "error": "You are not a member of this chat room" }
POST /api/chat/rooms/:roomId/messages Send a message to chat room 🔒 Auth

Headers

Header Value Required
Authorization Bearer <token> Yes
Content-Type application/json Yes

Path Parameters

Parameter Type Required Description
roomId string Yes Chat room ID

Request Body

Field Type Required Description
content string Yes Message content (max 2000 characters)

Example Request

{
  "content": "Looking forward to meeting everyone!"
}

Success Response (201)

{
  "message": {
    "id": "msg-uuid",
    "senderId": "user-uuid",
    "content": "Looking forward to meeting everyone!",
    "createdAt": "2026-02-07T12:45:00.000Z"
  }
}

Error Responses

// 400 Bad Request
{ "error": "Message content is required" }
{ "error": "Message content cannot be empty" }
{ "error": "Message content cannot exceed 2000 characters" }

// 403 Forbidden
{ "error": "You are not a member of this chat room" }
POST /api/chat/rooms/:roomId/leave Leave a chat room 🔒 Auth

Headers

Header Value Required
Authorization Bearer <token> Yes

Path Parameters

Parameter Type Required Description
roomId string Yes Chat room ID

Success Response (200)

{ "message": "Successfully left the chat room" }

Error Responses

// 403 Forbidden
{ "error": "You are not a member of this chat room" }
POST /api/chat/rooms/:roomId/rejoin Rejoin a chat room (requires confirmed booking) 🔒 Auth

Headers

Header Value Required
Authorization Bearer <token> Yes

Path Parameters

Parameter Type Required Description
roomId string Yes Chat room ID

Success Response (200)

{ "message": "Successfully rejoined the chat room" }

Error Responses

// 403 Forbidden
{ "error": "You must have a confirmed booking to join the chat room" }
{ "error": "You are already a member of this chat room" }

// 404 Not Found
{ "error": "Chat room not found" }

Admin

Administrative operations for managing organizers, events, reviews, and moderation. All endpoints require ADMIN role authorization.

GET /api/admin/dashboard/stats Get dashboard statistics

Get Admin Dashboard Statistics

Retrieve comprehensive statistics for the admin dashboard.

Parameter Type Description
No parameters required
Response (200 OK)
{
  "stats": {
    "organizersByStatus": {
      "PENDING": 5,
      "APPROVED": 42,
      "REJECTED": 3
    },
    "events": {
      "total": 156,
      "active": 148,
      "cancelled": 8
    },
    "users": 1250,
    "reviews": 890,
    "moderationLogs": 127
  }
}
GET /api/admin/organizers/all List organizer applications

Get All Organizers with Approval Status

List all organizers filtered by approval status.

Parameter Type Description
status query (optional) Filter by status: PENDING, APPROVED, or REJECTED
Response (200 OK)
{
  "organizers": [
    {
      "id": "org_123",
      "userId": "user_123",
      "organizationName": "Adventure Tours Co",
      "contactPerson": "John Doe",
      "contactNumber": "1234567890",
      "address": "123 Main St, City",
      "status": "APPROVED",
      "createdAt": "2025-01-15T10:30:00Z",
      "updatedAt": "2025-01-16T14:20:00Z",
      "eventCount": 12
    }
  ],
  "total": 45
}
GET /api/admin/organizers/pending List pending organizer applications

Get Pending Organizer Applications

Retrieve organizers awaiting approval.

Parameter Type Description
No parameters required
Response (200 OK)
{
  "organizers": [
    {
      "id": "org_456",
      "organizationName": "New Tours Ltd",
      "contactPerson": "Jane Smith",
      "contactNumber": "9876543210",
      "status": "PENDING",
      "createdAt": "2025-02-18T08:00:00Z"
    }
  ],
  "count": 5
}
POST /api/admin/organizers/:id/approve Approve organizer application

Approve Organizer Application

Approve a pending organizer application.

Parameter Type Description
id path Organizer ID
Request Body
{}
Response (200 OK)
{
  "message": "Organizer approved successfully",
  "organizer": {
    "id": "org_456",
    "status": "APPROVED",
    "updatedAt": "2025-02-18T10:30:00Z"
  }
}
Response (400 Bad Request)
{
  "error": "Organizer not found or not in PENDING status"
}
POST /api/admin/organizers/:id/reject Reject organizer application

Reject Organizer Application

Reject a pending organizer application with reason.

Parameter Type Description
id path Organizer ID
Request Body
{
  "reason": "Invalid business registration",
  "code": "INVALID_REGISTRATION"
}
Response (200 OK)
{
  "message": "Organizer rejected successfully",
  "organizer": {
    "id": "org_456",
    "status": "REJECTED",
    "rejectionReason": "Invalid business registration",
    "rejectionCode": "INVALID_REGISTRATION",
    "updatedAt": "2025-02-18T10:35:00Z"
  }
}
GET /api/admin/organizers/:id/detail Get organizer detail for review

Get Organizer Detail

Fetch organizer profile, owner user info, event summaries, and moderation history before approval.

Parameter Type Description
id path Organizer ID
Response (200 OK)
{
  "id": "org_123",
  "status": "PENDING",
  "organizationName": "Adventure Tours Co",
  "user": {
    "id": "user_123",
    "name": "Alice",
    "email": "alice@example.com"
  },
  "userRoles": ["USER"],
  "eventCount": 2,
  "events": [
    {
      "id": "evt_101",
      "title": "City Walk",
      "status": "PENDING"
    }
  ],
  "moderationLogs": []
}
GET /api/admin/events/top Get top performing events

Get Top Performing Events

Retrieve events with highest bookings and ratings.

Parameter Type Description
limit query (optional) Number of events to return (default: 10)
Response (200 OK)
{
  "events": [
    {
      "id": "evt_123",
      "title": "Mountain Expedition 2025",
      "bookingCount": 45,
      "averageRating": 4.8,
      "totalRevenue": 22500,
      "organizer": "Adventure Tours Co"
    }
  ],
  "count": 10
}
GET /api/admin/events/:id/detail Get event detail for review

Get Event Detail

Fetch event, organizer info, booking/review signals, and moderation history before approval.

Parameter Type Description
id path Event ID
Response (200 OK)
{
  "id": "evt_123",
  "status": "PENDING",
  "title": "Mountain Expedition 2025",
  "organizer": {
    "id": "org_123",
    "status": "APPROVED",
    "user": {
      "id": "user_123",
      "name": "Alice",
      "email": "alice@example.com"
    }
  },
  "metrics": {
    "totalBookings": 8,
    "confirmedBookings": 5,
    "reviewCount": 3
  },
  "moderationLogs": []
}
POST /api/admin/events/:id/approve Approve pending event

Approve Event

Approve a pending event submitted by an approved organizer.

Parameter Type Description
id path Event ID
Request Body
{}
Response (200 OK)
{
  "message": "Event approved successfully",
  "event": {
    "id": "evt_123",
    "status": "CONFIRMED",
    "approvedBy": "admin_001"
  }
}
POST /api/admin/events/:id/cancel Cancel event

Cancel Event

Cancel an active event.

Parameter Type Description
id path Event ID
Request Body
{}
Response (200 OK)
{
  "message": "Event cancelled successfully",
  "event": {
    "id": "evt_123",
    "status": "CANCELLED",
    "updatedAt": "2025-02-18T11:00:00Z"
  }
}
DELETE /api/admin/events/:id Delete event

Delete Event

Permanently delete an event. Cannot delete events with confirmed bookings.

Parameter Type Description
id path Event ID
Response (200 OK)
{
  "message": "Event deleted successfully",
  "id": "evt_123"
}
Response (400 Bad Request)
{
  "error": "Cannot delete event with confirmed bookings"
}
GET /api/admin/reviews/suspicious Get suspicious reviews

Get Suspicious Reviews

Retrieve reviews that may require moderation (ratings ≤ 1 or failed sentiment analysis).

Parameter Type Description
No parameters required
Response (200 OK)
{
  "reviews": [
    {
      "id": "rev_123",
      "eventId": "evt_123",
      "userId": "user_456",
      "rating": 1,
      "content": "Terrible experience",
      "sentiment": {
        "score": -0.95,
        "label": "NEGATIVE"
      },
      "createdAt": "2025-02-18T09:00:00Z"
    }
  ],
  "count": 3
}
POST /api/admin/reviews/:id/flag Flag review for moderation

Flag Review for Moderation

Mark a review as flagged for manual review.

Parameter Type Description
id path Review ID
Request Body
{
  "reason": "Potentially inappropriate language"
}
Response (200 OK)
{
  "message": "Review flagged successfully",
  "review": {
    "id": "rev_123",
    "flagged": true,
    "flagReason": "Potentially inappropriate language"
  }
}
GET /api/admin/logs/moderation Get moderation logs

Get Moderation Logs

Retrieve audit trail of admin actions.

Parameter Type Description
page query (optional) Page number (default: 1)
limit query (optional) Results per page (default: 20)
Response (200 OK)
{
  "logs": [
    {
      "id": "log_123",
      "adminId": "admin_user_123",
      "action": "APPROVE_ORGANIZER",
      "targetId": "org_456",
      "targetType": "ORGANIZER",
      "details": {
        "organizationName": "Adventure Tours Co",
        "reason": "Verified registration and credentials"
      },
      "timestamp": "2025-02-18T10:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 127
  }
}
GET /api/admin/stats/organizers Get organizer statistics

Get Organizer Statistics

Retrieve statistics about organizers by status.

Parameter Type Description
No parameters required
Response (200 OK)
{
  "stats": {
    "statuses": {
      "PENDING": 5,
      "APPROVED": 42,
      "REJECTED": 3
    },
    "activeEvents": 98,
    "totalOrganizers": 50
  }
}
GET /api/admin/stats/events Get event statistics

Get Event Statistics

Retrieve statistics about events.

Parameter Type Description
No parameters required
Response (200 OK)
{
  "stats": {
    "total": 156,
    "active": 148,
    "cancelled": 8
  }
}
GET /api/admin/stats/bookings Get booking statistics

Get Booking Statistics

Retrieve statistics about bookings by status.

Parameter Type Description
No parameters required
Response (200 OK)
{
  "stats": {
    "total": 542,
    "confirmed": 485,
    "cancelled": 57
  }
}
GET /api/admin/organizers/top Get top organizers

Get Top Organizers

Retrieve top performing organizers by event count and ratings.

Parameter Type Description
limit query (optional) Number of organizers to return (default: 10)
Response (200 OK)
{
  "organizers": [
    {
      "id": "org_123",
      "organizationName": "Adventure Tours Co",
      "eventCount": 45,
      "averageRating": 4.7,
      "totalBookings": 285
    }
  ],
  "count": 10
}