Skip to main content

Overview

Conversations represent chat threads between two users. Each conversation can optionally be linked to a horse listing (e.g., when a buyer contacts a seller about a specific horse).

Authentication

All conversation endpoints require authentication via JWT token in the Authorization header.
Authorization: Bearer <your_jwt_token>

Create or Get Conversation

curl -X POST https://api.horsetrust.com/api/chat/conversations \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient_id": "507f1f77bcf86cd799439011",
    "horse_id": "507f1f77bcf86cd799439012"
  }'
{
  "success": true,
  "data": {
    "_id": "65a1b2c3d4e5f6a7b8c9d0e1",
    "participants": [
      "507f1f77bcf86cd799439010",
      "507f1f77bcf86cd799439011"
    ],
    "horse_id": "507f1f77bcf86cd799439012",
    "last_message": {
      "text": "Is this horse still available?",
      "sender_id": "507f1f77bcf86cd799439010",
      "sent_at": "2024-03-15T10:30:00.000Z",
      "is_read": false
    },
    "created_at": "2024-03-15T10:30:00.000Z",
    "updated_at": "2024-03-15T10:30:00.000Z"
  }
}

POST /api/chat/conversations

Creates a new conversation or returns an existing one between the authenticated user and the recipient. If a conversation already exists between these two users (optionally for the same horse), the existing conversation is returned.
recipient_id
string
required
MongoDB ObjectId of the user to start a conversation with. Must be a valid ObjectId and cannot be the current user’s ID.
horse_id
string
MongoDB ObjectId of the horse listing this conversation is about. Optional. If provided, the conversation will be linked to this specific horse.

Response Fields

success
boolean
required
Indicates if the request was successful
data
object
The conversation object
_id
string
Unique conversation identifier
participants
array
Array of exactly 2 user ObjectIds representing the participants in the conversation
horse_id
string
MongoDB ObjectId of the related horse listing (if applicable)
last_message
object
Snapshot of the most recent message in the conversation
text
string
Message content
sender_id
string
ObjectId of the user who sent the message
sent_at
string
ISO 8601 timestamp when the message was sent
is_read
boolean
Whether the message has been read by the recipient
created_at
string
ISO 8601 timestamp when the conversation was created
updated_at
string
ISO 8601 timestamp when the conversation was last updated
message
string
Error message (only present when success is false)

Error Responses

  • 400 Bad Request: Invalid recipient ID or attempting to message yourself
  • 500 Internal Server Error: Server error occurred

List Conversations

curl https://api.horsetrust.com/api/chat/conversations \
  -H "Authorization: Bearer <token>"
{
  "success": true,
  "data": [
    {
      "_id": "65a1b2c3d4e5f6a7b8c9d0e1",
      "participants": [
        {
          "_id": "507f1f77bcf86cd799439010",
          "full_name": "John Smith",
          "profile_picture_url": "https://cdn.horsetrust.com/users/john.jpg",
          "seller_profile": {
            "is_verified_badge": true
          }
        },
        {
          "_id": "507f1f77bcf86cd799439011",
          "full_name": "Jane Doe",
          "profile_picture_url": "https://cdn.horsetrust.com/users/jane.jpg",
          "seller_profile": {
            "is_verified_badge": false
          }
        }
      ],
      "horse_id": {
        "_id": "507f1f77bcf86cd799439012",
        "name": "Thunder",
        "photos": [
          {
            "url": "https://cdn.horsetrust.com/horses/thunder-1.jpg",
            "is_primary": true
          }
        ]
      },
      "last_message": {
        "text": "Yes, Thunder is still available!",
        "sender_id": "507f1f77bcf86cd799439011",
        "sent_at": "2024-03-15T10:35:00.000Z",
        "is_read": false
      },
      "created_at": "2024-03-15T10:30:00.000Z",
      "updated_at": "2024-03-15T10:35:00.000Z"
    }
  ]
}

GET /api/chat/conversations

Returns all conversations for the authenticated user, sorted by most recently updated first. Results include populated participant details and horse information.

Response Fields

success
boolean
required
Indicates if the request was successful
data
array
Array of conversation objects sorted by updated_at (most recent first)
_id
string
Unique conversation identifier
participants
array
Array of populated user objects
_id
string
User’s unique identifier
full_name
string
User’s full name
profile_picture_url
string
URL to the user’s profile picture
seller_profile
object
Seller profile information
is_verified_badge
boolean
Whether the seller has a verified badge
horse_id
object
Populated horse object (if conversation is linked to a horse)
_id
string
Horse’s unique identifier
name
string
Horse’s name
photos
array
Array of horse photos
last_message
object
Most recent message in the conversation (see Create or Get Conversation for fields)
created_at
string
ISO 8601 timestamp when the conversation was created
updated_at
string
ISO 8601 timestamp when the conversation was last updated

Error Responses

  • 500 Internal Server Error: Server error occurred

Socket.io Events

Join Conversation Room

Join a specific conversation room to receive real-time messages.
socket.emit('join_conversation', conversationId);
conversationId
string
required
The ID of the conversation to join

New Message Event

Receive new messages in conversations you’ve joined.
socket.on('new_message', (message) => {
  console.log('New message:', message);
});
Event Payload:
{
  "_id": "65a1b2c3d4e5f6a7b8c9d0e3",
  "conversation_id": "65a1b2c3d4e5f6a7b8c9d0e1",
  "sender_id": {
    "_id": "507f1f77bcf86cd799439010",
    "full_name": "John Smith",
    "profile_picture_url": "https://cdn.horsetrust.com/users/john.jpg"
  },
  "text": "Is this horse still available?",
  "is_read": false,
  "sent_at": "2024-03-15T10:30:00.000Z"
}

Message Notification Event

Receive notifications when someone sends you a message (delivered to your personal user room).
socket.on('message_notification', (notification) => {
  console.log('New message notification:', notification);
});
Event Payload:
{
  "conversation_id": "65a1b2c3d4e5f6a7b8c9d0e1",
  "sender": "507f1f77bcf86cd799439010",
  "preview": "Is this horse still available?"
}
The preview field contains the first 60 characters of the message text.

Data Model

Conversation Schema

{
  participants: [ObjectId, ObjectId],  // Exactly 2 users (required)
  horse_id: ObjectId,                   // Optional reference to Horse
  last_message: {
    text: String,
    sender_id: ObjectId,
    sent_at: Date,
    is_read: Boolean
  },
  created_at: Date,
  updated_at: Date
}

Validation Rules

  • Conversations must have exactly 2 participants
  • Participants must be valid user ObjectIds
  • Users cannot create conversations with themselves
  • The last_message field is automatically updated when new messages are sent

Indexes

  • participants: Used for efficiently finding all conversations for a user

Build docs developers (and LLMs) love