Skip to main content
GET
/
api
/
threads
/
{id}
/
messages
curl -X GET 'http://localhost:5079/api/threads/f47ac10b-58cc-4372-a567-0e02b2c3d479/messages' \
  -H 'Authorization: Bearer YOUR_JWT_TOKEN'
{
  "items": [
    {
      "message_id": "msg-uuid-here",
      "thread_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "prompt_text": "What is AI?",
      "model1_id": "model-uuid-1",
      "model2_id": "model-uuid-2",
      "model1_response": "AI is artificial intelligence...",
      "model2_response": "Artificial intelligence refers to...",
      "comparison_id": "comparison-uuid",
      "model1_time_ms": 450,
      "model2_time_ms": 520,
      "created_at": "2024-01-15T10:30:00.000Z"
    }
  ]
}

Authentication

Conditional (Line 198): [AllowAnonymous] Follows same access rules as GET /api/threads/

Path Parameters

id
string
required
Thread UUIDFormat: Valid GUIDValidation: Route constraint :guid (Line 197)

Response

items
array
Array of message objects
curl -X GET 'http://localhost:5079/api/threads/f47ac10b-58cc-4372-a567-0e02b2c3d479/messages' \
  -H 'Authorization: Bearer YOUR_JWT_TOKEN'
{
  "items": [
    {
      "message_id": "msg-uuid-here",
      "thread_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "prompt_text": "What is AI?",
      "model1_id": "model-uuid-1",
      "model2_id": "model-uuid-2",
      "model1_response": "AI is artificial intelligence...",
      "model2_response": "Artificial intelligence refers to...",
      "comparison_id": "comparison-uuid",
      "model1_time_ms": 450,
      "model2_time_ms": 520,
      "created_at": "2024-01-15T10:30:00.000Z"
    }
  ]
}

Authorization Logic

Identical to GET /api/threads/ (Lines 203-249):
// First check thread access (same logic as GetThread)
var thread = await _threadsService.GetThreadAsync(threadId);

// Apply same visibility + feature flag checks
if (!(publicSharingEnabled && (thread.Visibility == "public" || "unlisted"))) {
    // Require auth + ownership check
}

Access Control Matrix

FlagVisibilityAuthAccess
ONpublicNo✅ Allowed
ONunlistedNo✅ Allowed
ONprivateNo❌ 401
ONprivateYes (owner)✅ Allowed
ONprivateYes (other)❌ 403
OFF*No❌ 401
OFF*Yes (owner)✅ Allowed
OFF*Yes (other)❌ 403

Side Effects

Database Reads (Lines 204, 216, 251):
  • SELECT from threads table WHERE thread_id = {id}
  • SELECT from system_settings table WHERE key = 'public_sharing'
  • SELECT from thread_messages table WHERE thread_id = {id}
No Database Writes: Read-only endpoint Message Ordering: Not specified by API contract (service-defined, likely chronological)

Permissions

Same as Thread Access:
  • If user can read thread, user can read messages
  • No separate message-level permissions
Cascade Rule: Message visibility = Thread visibility

Edge Cases

  1. Thread doesn’t exist: 404 (Lines 206-214)
  2. Thread exists but has zero messages: Returns {"items": []} (Line 253)
  3. Invalid GUID format: 400 (route constraint)
  4. Deleted thread: 404 (service returns null for thread)
  5. Orphaned messages (thread deleted): Cannot occur (thread lookup first)
  6. Partial message data (model2 null in single-chat): Nullable fields return null

Error Conditions

CodeHTTPCauseController Line
NOT_FOUND404Thread doesn’t exist206-214
UNAUTHORIZED401Auth required but missing230-238
FORBIDDEN403Private thread, wrong user240-248
MESSAGES_ERROR500Service exception255-263
Exception Handling (Lines 255-263):
catch (Exception ex) {
    return StatusCode(500, new { error = ex.Message, code = "MESSAGES_ERROR" });
}

Behavioral Guarantees

Two-Step Verification (Lines 204-249):
  1. Thread existence + access check
  2. Messages retrieval
Atomicity: Not transactional
  • Thread could be deleted between checks (race condition)
  • Service behavior on race condition not enforced by server contract
Pagination: Not supported
  • Returns ALL messages for thread
  • No limit parameter
  • Could cause performance issues for large threads

Performance Characteristics

Database Queries: 3 queries per request
  1. Thread lookup
  2. Feature flag lookup
  3. Messages retrieval
Response Size: Unbounded (proportional to message count) Index Requirements:
  • thread_messages.thread_id should be indexed
  • threads.thread_id primary key
Performance Risk: Large threads (100+ messages) may cause slow responses

Message Schema Details

Single-Chat Mode:
  • model1_id: Populated
  • model2_id: NULL
  • model1_response: Populated
  • model2_response: NULL
  • comparison_id: NULL
Dual-Chat Mode:
  • model1_id: Populated
  • model2_id: Populated
  • model1_response: Populated
  • model2_response: Populated
  • comparison_id: Populated (links to comparisons table)
Comparison ID Usage:
  • Can be used with GET /api/arena/model-stats to see vote data
  • Links message to arena comparison for voting